整数のリストのリストで重複を見つけるための最良の方法は何ですか(どの位置にいても)。この問題に対処するための最良の方法であるコードは必要ありません。
例えば:
List<List<int>> TestData = new List<List<int>>
{
new List<int> { 1, 2, 3 },
new List<int> { 2, 1, 3 },
new List<int> { 6, 8, 3 },
new List<int> { 9, 2, 4 },
};
これは戻ってくるという考えです
2x) 1,2,3
1x) 6,8,3
1x) 9,2,4
私はこの一見非常に単純な質問に頭を悩ませてきましたが、何らかの理由でそれを理解することができません。誰かが助けてくれるといいのですが、私が言ったように、コードは必要ありませんが、とても感謝しています。
このサイトはコードに関するものではありませんが、これは機能します
IEqualityComparer<List<int>> listComparer = new ListComparer();
testData.ForEach(l => l.Sort());
var distinctLists = testData
.GroupBy(j => j, listComparer)
.Select(group => new { List = group.Key, Count = group.Count() });
public class ListComparer : IEqualityComparer<List<int>>
{
public bool Equals(List<int> x, List<int> y)
{
if (x.Count != y.Count)
return false;
for (int i = 0; i < x.Count; i++)
if (x[i] != y[i]) return false;
return true;
}
public int GetHashCode(List<int> x) => x.Count;
}
ブルートフォースアプローチ:
TestData
のすべてのリストを並べ替えますTestData
(重複するリストが必然的に互いに続くように)TestData
を繰り返します。すべてのリストについて、以下のリストがいくつあるかを数えて、重複を見つけます(重複が見つかった場合は、メインの繰り返しでスキップします)。スマートなアプローチ:
TestData
にインデックスと長さとともに保存するリストを作成し、チェックサムと長さで並べ替えます。このアプローチは、同じチェックサムと長さを持つリストのみが等しい場合があるため、ソートおよび比較するリストの数を減らすという事実に基づいています。
この2番目の方法は実装がより複雑ですが、より高価なソートを実行し、本当に必要な場合にのみ比較するという利点があります。アルゴリズムを適応させて、ソートをスマートな比較に置き換えることができます
リストのエレガントな辞書式ソート を含む、最初のアプローチの小さな実装を次に示します。
// Sort every list in the list
for (int i = 0; i < TestData.Count; i++)
TestData[i].Sort();
// Order the list of lists using a lexicographic sort
TestData.Sort((x, y) => {
var result = x.Zip(y, Tuple.Create)
.Select(z => z.Item1.CompareTo(z.Item2))
.FirstOrDefault(k => k != 0);
return result == 0 && !x.Any() ? -1 : result;
});
var sorted = TestData;
// Iterating through the ordered list of list to spot the duplicates
List<int> t=null;
int cpt = 1;
foreach (var l in sorted)
{
if (t != null) // do nothing for the very first list
{
// in all other cases, compare list with the previous one
var a = t.SequenceEqual(l);
if (a) // if it's the same, increment occurrence counter
cpt++;
else // if not, show the duplicates and restart counting
{
Console.Write("{0} x ", cpt);
WriteList(t);
cpt = 1;
}
}
t = l;
}
if (t!=null) // process the last element outside the loop
{
Console.Write("{0} x ", cpt);
WriteList(t);
}
次のテスト入力を使用します。
List<List<int>> TestData
= new List<List<int>> { new List<int> { 1, 2, 3 },
new List<int> { 1, 8, 2 },
new List<int> { 2, 1, 3 },
new List<int> { 9, 2, 4 } };
期待される出力を生成します:
2 x 1 2 3
1 x 1 2 8
1 x 2 4 9
各リストのソートされたバージョンでグループ化し、各グループの長さを取得する場合、これは実装が非常に簡単です。 Scalaでは、これは:
val groups = testData groupBy {_.sorted} mapValues {_.length}
groups foreach println
/* output:
(List(3, 6, 8),1)
(List(2, 4, 9),1)
(List(1, 2, 3),2)
*/
当然、注文や出力フォーマットの要件がある場合は、さらに複雑になります。 C#はわかりませんが、LINQには GroupBy があり、非常によく似ています。
リストが複製されるということを定義する必要があります。注文は気にしないようです。{1、2、3}は{2、1、3}の重複ですが、重複した数字も無視するため、{1、2、3}は{2の重複です、1、1、3}?
決定した同等性の定義を使用してIEqualityComparer
を記述します。 (例:セットまたは順序付きリストとして比較)
等値比較子でGroupBy
を使用して類似のリストをグループ化すると、各グループの重複のCount
を取得できます。