web-dev-qa-db-fra.com

C # LINQ trouve les doublons dans la liste

À l'aide de LINQ, à partir d'un List<int>, comment puis-je récupérer une liste contenant des entrées répétées plusieurs fois et leurs valeurs?

233
Mirko Arcese

Le moyen le plus simple de résoudre le problème consiste à regrouper les éléments en fonction de leur valeur, puis à choisir un représentant du groupe s'il existe plusieurs éléments dans le groupe. Dans LINQ, cela se traduit par:

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

Si vous voulez savoir combien de fois les éléments sont répétés, vous pouvez utiliser:

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

Cela renverra une List de type anonyme et chaque élément aura les propriétés Element et Counter, pour récupérer les informations dont vous avez besoin.

Et enfin, si vous cherchez un dictionnaire, vous pouvez utiliser

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

Cela retournera un dictionnaire, avec votre élément en tant que clé et le nombre de répétitions en tant que valeur.

414
Save

Savoir si un énumérable contient un doublon :

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

Déterminez si toutes les valeurs d'un énumérable sont unique :

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

Une autre façon utilise HashSet:

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

Si vous voulez des valeurs uniques dans votre liste de doublons:

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)).ToList().Distinct().ToList();

Voici la même solution qu'une méthode d'extension générique:

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);
  }
}
18
HuBeZa

Tu peux le faire:

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

Avec ces méthodes d'extension:

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();
    }
}

L'utilisation de IsMultiple () dans la méthode Duplicates est plus rapide que Count (), car elle n'itère pas la collection entière.

10
Alex Siepman

J'ai créé une extension pour répondre à cela, vous pouvez l'inclure dans vos projets, je pense que cela revient le plus souvent lorsque vous recherchez des doublons dans List ou Linq.

Exemple:

//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
        */
}
6
Ricardo Figueiredo

Ensemble complet d'extensions Linq to SQL de fonctions dupliquées vérifiées dans MS SQL Server. Sans utiliser .ToList () ou IEnumerable. Ces requêtes s'exécutent dans SQL Server plutôt qu'en mémoire. . Les résultats ne reviennent qu'à la mémoire.

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()));
}
1
GeoB

Pour trouver les valeurs en double uniquement:

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

Par exemple, . Var liste = new [] {1,2,3,1,4,2};

alors group by groupera les numéros par leurs touches et conservera le compte (nombre de répétitions) avec. Après cela, nous vérifions simplement les valeurs qui se sont répétées plus d’une fois.

Pour trouver les valeurs uniuqe uniquement:

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

Par exemple, . Var liste = new [] {1,2,3,1,4,2};

alors group by groupera les numéros par leurs touches et conservera le compte (nombre de répétitions) avec. Après cela, nous vérifions simplement les valeurs qui n’ont été répétées qu’une seule fois et qui sont uniques.

1
LAV VISHWAKARMA