C#LINQはリスト内の重複を検出します


回答:


566

問題を解決する最も簡単な方法は、値に基づいて要素をグループ化し、グループに複数の要素がある場合は、グループの代表を選択することです。LINQでは、これは次のように変換されます。

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .Select(y => y.Key)
              .ToList();

要素が繰り返される回数を知りたい場合は、以下を使用できます。

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .Select(y => new { Element = y.Key, Counter = y.Count() })
              .ToList();

これはList匿名型のを返し、各要素にはプロパティElementとがありCounter、必要な情報を取得します。

そして最後に、それがあなたが探している辞書であれば、あなたは使うことができます

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .ToDictionary(x => x.Key, y => y.Count());

これは、要素をキーとして、辞書が繰り返される回数を値として返します。


ちょっと不思議ですが、複製されたintがn int配列に分散されているとしましょう。ディクショナリとforループを使用して、どの配列に複製が含まれているかを理解し、分散のロジックに従ってそれを削除します。最も速い方法(linq疑問)その結果を達成しますか?よろしくお願いします。
ミルコArcese

私はこのようなことをしています: code for(int i = 0; i <duplicates.Count; i ++){int duplicate = duplicates [i]; duplicatesLocation.Add(duplicate、new List <int>()); for(int k = 0; k <hitsList.Length; k ++){if(hitsList [k] .Contains(duplicate)){duplicatesLocation.ElementAt(i).Value.Add(k); }} //いくつかのルールに従って重複を削除します。}code
Mirko Arcese 2013

配列のリストで重複を見つけたい場合は、SelectManyを見てください
保存

リストの配列で重複を検索していますが、selectmanyがそれを理解するのにどのように役立つかわかりませんでした
Mirko Arcese

1
Count()の代わりにSkip(1).Any()を使用する方が効率的である場合、コレクションに複数の要素があるかどうかを確認します。1000個の要素を持つコレクションを想像してみてください。Skip(1).Any()は、2番目の要素が見つかると、複数あることを検出します。Count()を使用するには、コレクション全体にアクセスする必要があります。
Harald Coppoolse 2017年

133

列挙型に重複が含まれているかどうかを確認します。

var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);

列挙型のすべての値が一意であるかどうかを確認ます。

var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);

これらが必ずしもブール値の反対ではない可能性はありますか?anyDuplicate ==!allUniqueすべてのケースで。
Garr Godfrey

1
@GarrGodfreyそれらは常にブール値の反対です
Caltor '19 / 11/18

21

別の方法は使用していHashSetます:

var hash = new HashSet<int>();
var duplicates = list.Where(i => !hash.Add(i));

重複リストに一意の値が必要な場合:

var myhash = new HashSet<int>();
var mylist = new List<int>(){1,1,2,2,3,3,3,4,4,4};
var duplicates = mylist.Where(item => !myhash.Add(item)).Distinct().ToList();

以下は、一般的な拡張メソッドと同じソリューションです。

public static class Extensions
{
  public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IEqualityComparer<TKey> comparer)
  {
    var hash = new HashSet<TKey>(comparer);
    return source.Where(item => !hash.Add(selector(item))).ToList();
  }

  public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  {
    return source.GetDuplicates(x => x, comparer);      
  }

  public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
  {
    return source.GetDuplicates(selector, null);
  }

  public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source)
  {
    return source.GetDuplicates(x => x, null);
  }
}

これは期待どおりに機能しません。List<int> { 1, 2, 3, 4, 5, 2 }ソースとして使用するIEnumerable<int>と、結果はの値を持つ要素が1つあります1(正しい重複値は2です)
BCA

@BCA昨日、私はあなたが間違っていると思います。この例を確認してください:dotnetfiddle.net/GUnhUl
HuBeZa

フィドルは正しい結果を出力します。ただし、そのConsole.WriteLine("Count: {0}", duplicates.Count());すぐ下に行を追加して印刷し6ます。この関数の要件について何か見落としがない限り、結果として得られるコレクションには1つのアイテムしかありません。
BCA 2017年

@BCA昨日、これはLINQ遅延実行が原因のバグです。ToList問題を修正するために追加しましたが、メソッドが呼び出されるとすぐに実行され、結果を繰り返し処理するときではありません。
HuBeZa 2017年

var hash = new HashSet<int>(); var duplicates = list.Where(i => !hash.Add(i));重複のすべての出現を含むリストにつながります。したがって、リストに2の4つのオカレンスがある場合、HashSetに追加できるのは2つのうちの1つだけなので、複製リストには2つの3つのオカレンスが含まれます。あなたはそれぞれの重複のために一意の値を格納するためのあなたのリストをしたい場合は、代わりにこのコードを使用:var duplicates = mylist.Where(item => !myhash.Add(item)).ToList().Distinct().ToList();
solid_luffy

10

あなたはこれを行うことができます:

var list = new[] {1,2,3,1,4,2};
var duplicateItems = list.Duplicates();

これらの拡張メソッドを使用すると:

public static class Extensions
{
    public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        var grouped = source.GroupBy(selector);
        var moreThan1 = grouped.Where(i => i.IsMultiple());
        return moreThan1.SelectMany(i => i);
    }

    public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source)
    {
        return source.Duplicates(i => i);
    }

    public static bool IsMultiple<T>(this IEnumerable<T> source)
    {
        var enumerator = source.GetEnumerator();
        return enumerator.MoveNext() && enumerator.MoveNext();
    }
}

DuplicatesメソッドでIsMultiple()を使用すると、コレクション全体が繰り返されないため、Count()より高速です。


グループ化参照ソースを見ると、それCount() 事前に計算されており、ソリューションが遅くなる可能性があります。
Johnbot、2015年

@Johnbot。あなたは正しいです、この場合、それはより速くて、実装は決して変わらないでしょう...しかし、それはIGroupingの背後にある実装クラスの実装詳細に依存します。私の実装では、コレクション全体が繰り返されることはありません。
Alex Siepman、2015年

したがって、[ Count()]を数えることは、基本的にリスト全体を繰り返すこととは異なります。Count()は事前に計算されていますが、リスト全体を反復することはできません。
Jogi

@rehan khan:Count()とCount()の違いがわかりません
Alex Siepman

2
@RehanKhan:IsMultipleはCount()を実行していないため、2つのアイテムの直後に停止します。Take(2).Count> = 2;と同じです。
Alex Siepman 2017

6

これに対応するための拡張を作成しました。プロジェクトに含めることができます。これは、リストまたはLinqで重複を検索した場合に最も多く返されると思います。

例:

//Dummy class to compare in list
public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public Person(int id, string name, string surname)
    {
        this.Id = id;
        this.Name = name;
        this.Surname = surname;
    }
}


//The extention static class
public static class Extention
{
    public static IEnumerable<T> getMoreThanOnceRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
    { //Return only the second and next reptition
        return extList
            .GroupBy(groupProps)
            .SelectMany(z => z.Skip(1)); //Skip the first occur and return all the others that repeats
    }
    public static IEnumerable<T> getAllRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
    {
        //Get All the lines that has repeating
        return extList
            .GroupBy(groupProps)
            .Where(z => z.Count() > 1) //Filter only the distinct one
            .SelectMany(z => z);//All in where has to be retuned
    }
}

//how to use it:
void DuplicateExample()
{
    //Populate List
    List<Person> PersonsLst = new List<Person>(){
    new Person(1,"Ricardo","Figueiredo"), //fist Duplicate to the example
    new Person(2,"Ana","Figueiredo"),
    new Person(3,"Ricardo","Figueiredo"),//second Duplicate to the example
    new Person(4,"Margarida","Figueiredo"),
    new Person(5,"Ricardo","Figueiredo")//third Duplicate to the example
    };

    Console.WriteLine("All:");
    PersonsLst.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        All:
        1 -> Ricardo Figueiredo
        2 -> Ana Figueiredo
        3 -> Ricardo Figueiredo
        4 -> Margarida Figueiredo
        5 -> Ricardo Figueiredo
        */

    Console.WriteLine("All lines with repeated data");
    PersonsLst.getAllRepeated(z => new { z.Name, z.Surname })
        .ToList()
        .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        All lines with repeated data
        1 -> Ricardo Figueiredo
        3 -> Ricardo Figueiredo
        5 -> Ricardo Figueiredo
        */
    Console.WriteLine("Only Repeated more than once");
    PersonsLst.getMoreThanOnceRepeated(z => new { z.Name, z.Surname })
        .ToList()
        .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        Only Repeated more than once
        3 -> Ricardo Figueiredo
        5 -> Ricardo Figueiredo
        */
}

1
Count()の代わりにSkip(1).Any()の使用を検討してください。1000の重複がある場合、Skip(1).Any()は2番目の重複を見つけた後に停止します。Count()は1000の要素すべてにアクセスします。
Harald Coppoolse 2017年

1
この拡張メソッドを追加する場合は、他の回答のいずれかで推奨されているように、GroupByの代わりにHashSet.Addの使用を検討してください。HashSet.Addが重複を見つけるとすぐに停止します。複数の要素を持つグループが見つかった場合でも、GroupByはすべての要素をグループ化し続けます
Harald Coppoolse '26 / 10/26

6

重複する値のみを見つけるには:

var duplicates = list.GroupBy(x => x.Key).Any(g => g.Count() > 1);

例えば。var list = new [] {1,2,3,1,4,2};

そのため、group byは、キーによって数値をグループ化し、それを使用してカウント(繰り返し回数)を維持します。その後、2回以上繰り返された値をチェックしているだけです。

一意の値のみを検索するには:

var unique = list.GroupBy(x => x.Key).All(g => g.Count() == 1);

例えば。var list = new [] {1,2,3,1,4,2};

そのため、group byは、キーによって数値をグループ化し、それを使用してカウント(繰り返し回数)を維持します。その後、1回だけ繰り返された値が一意であることを確認するだけです。


以下のコードは、ユニークなアイテムも見つけます。var unique = list.Distinct(x => x)
Malu MN

1

MS SQL ServerでチェックされたDuplicates関数のLinq to SQL拡張機能の完全なセット。.ToList()またはIEnumerableを使用しない場合。これらのクエリは、メモリではなくSQL Serverで実行されます。。結果はメモリでのみ返されます。

public static class Linq2SqlExtensions {

    public class CountOfT<T> {
        public T Key { get; set; }
        public int Count { get; set; }
    }

    public static IQueryable<TKey> Duplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => s.Key);

    public static IQueryable<TSource> GetDuplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).SelectMany(s => s);

    public static IQueryable<CountOfT<TKey>> DuplicatesCounts<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(y => new CountOfT<TKey> { Key = y.Key, Count = y.Count() });

    public static IQueryable<Tuple<TKey, int>> DuplicatesCountsAsTuble<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => Tuple.Create(s.Key, s.Count()));
}

0

答えはありますが、なぜ機能しないのか理解できませんでした。

var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);

私の解決策はこの状況ではそのようなものです。

var duplicates = model.list
                    .GroupBy(s => s.SAME_ID)
                    .Where(g => g.Count() > 1).Count() > 0;
if(duplicates) {
    doSomething();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.