web-dev-qa-db-ja.com

C#リスト内の重複を判別

要件:並べ替えられていないリストで、重複が存在するかどうかを判断します。私がこれを行う典型的な方法は、n二乗のネストされたループです。私は他の人がこれをどのように解決するのか疑問に思っています。 Linqにはエレガントで高性能な方法がありますか?ラムダまたは比較演算子を使用する一般的なものはニースです。

61
kakridge

何かが足りない場合を除き、Distinct()を使用して簡単なもので逃げることができます。それはあなたが思いつくかもしれない最も複雑な実装ではないことは確かですが、重複が削除されるかどうかを教えてくれます:

var list = new List<string>();

// Fill the list

if(list.Count != list.Distinct().Count())
{
     // Duplicates exist
}
131
Justin Niessner

LINQを使用して複製を見つける :の方法に関するEric Whiteの記事によると、

重複を見つける簡単な方法は、識別子でグループ化するクエリを作成し、複数のメンバーを持つグループをフィルタリングすることです。次の例では、4と3が重複していることを知りたいと思います。

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);
foreach (var d in duplicates)
    Console.WriteLine(d); // 4,3
44
Ali

重複がリストの初期に存在する場合に短絡を許可するには、 HashSet<T> を追加して、その.Addメソッドの戻り値を確認します。

.Anyを使用することにより、重複が見つかったらすぐに列挙を短絡できます。

C#とVBの両方でのLINQ拡張メソッドは次のとおりです。

Cシャープ:

public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable)
{
    var knownKeys = new HashSet<T>();
    return enumerable.Any(item => !knownKeys.Add(item));
}

Visual Basic:

<Extension>
Public Function ContainsDuplicates(Of T)(ByVal enumerable As IEnumerable(Of T)) As Boolean
    Dim knownKeys As New HashSet(Of T)
    Return enumerable.Any(Function(item) Not knownKeys.Add(item))
End Function

no重複があるかどうかを確認するには、単にAnyAllに変更します

20
KyleMit

セット内のすべてのアイテムを配置し、セットのカウントがリストのカウントと異なる場合、重複があります。

bool hasDuplicates<T>(List<T> myList) {
    var hs = new HashSet<T>();

    for (var i = 0; i < myList.Count; ++i) {
        if (!hs.Add(myList[i])) return true;
    }
    return false;
}

すべてのリストを調べる必要がないため、Distinctよりも効率的である必要があります。

13
Trinidad

IEnumerable.GroupByメソッドを使用できます。

var list = new List<string> {"1", "2","3", "1", "2"};
var hasDuplicates = list.GroupBy(x => x).Any(x => x.Skip(1).Any());
2
johnsonlu

これらの線に沿ったものは比較的単純であり、重複の数を提供します。

var something = new List<string>() { "One", "One", "Two", "Three" };

var dictionary = new Dictionary<string, int>();

something.ForEach(s =>
    {
        if (dictionary.ContainsKey(s))
        {
            dictionary[s]++;
        }
        else
        {
            dictionary[s] = 1;
        }
    });

確かではありませんが、これはDistinctの実装に似ていると思います。

2
Ian P

整数または適切に順序付けられたセットを使用している場合、O(nlog n)パフォーマンスのためにバイナリツリーを使用します。

または、別のより高速なソート方法を見つけて、すべての値が前の値と異なることを確認します。

1
andrewjs

IEnumerableにDistinct()拡張メソッドを使用できます

1

つかいます - Enumerable.Any with HashSet.Addのような:

List<string> list = new List<string> {"A", "A", "B", "C", "D"};
HashSet<string> hashSet = new HashSet<string>();
if(list.Any(r => !hashSet.Add(r)))
{
   //duplicate exists. 
}

HashSet.Addは、アイテムが既にfalseに存在する場合、HashSetを返します。これはリスト全体を反復しません。

1
Habib

Distinct()ステートメントを使用して、一意のレコードを見つけることができます。次に、次のような元の汎用リストと比較します。

  if (dgCoil.ItemsSource.Cast<BLL.Coil>().ToList().Count != dgCoil.ItemsSource.Cast<BLL.Coil>().Select(c => c.CoilNo).Distinct().Count())
  {    
    //Duplicate detected !!
    return;
  }
0
Murat ÜRKMEZ