C# LINQ encuentra duplicados en la lista

Resuelto Mirko Arcese asked hace 11 años • 13 respuestas

Usando LINQ, desde a List<int>, ¿cómo puedo recuperar una lista que contiene entradas repetidas más de una vez y sus valores?

Mirko Arcese avatar Aug 31 '13 17:08 Mirko Arcese
Aceptado

La forma más sencilla de resolver el problema es agrupar los elementos según su valor y luego elegir un representante del grupo si hay más de un elemento en el grupo. En LINQ, esto se traduce en:

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

Si quieres saber cuántas veces se repiten los elementos, puedes utilizar:

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

Esto devolverá un Listtipo anónimo y cada elemento tendrá las propiedades Elementy Counterpara recuperar la información que necesita.

Y por último, si lo que busca es un diccionario, puede utilizar

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

Esto devolverá un diccionario, con su elemento como clave y el número de veces que se repite como valor.

Save avatar Aug 31 '2013 10:08 Save

Descubra si un enumerable contiene algún duplicado :

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

Descubra si todos los valores de un enumerable son únicos :

var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);
maxbeaudoin avatar Dec 01 '2014 17:12 maxbeaudoin

Para encontrar solo los valores duplicados:

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

P.ej

var list = new[] {1,2,3,1,4,2};

GroupByagrupará los números por sus claves y mantendrá la cuenta (número de veces que se repite) con ello. Después de eso, solo estamos verificando los valores que se han repetido más de una vez.

Para encontrar sólo los valores únicos:

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

P.ej

var list = new[] {1,2,3,1,4,2};

GroupByagrupará los números por sus claves y mantendrá el conteo (número de veces que se repite) con ello. Después de eso, solo estamos verificando que los valores que se han repetido solo una vez sean únicos.

Lav Vishwakarma avatar Nov 09 '2018 05:11 Lav Vishwakarma

Otra forma es usar HashSet:

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

Si desea valores únicos en su lista de duplicados:

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

Aquí está la misma solución que un método de extensión genérico:

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);
  }
}
HuBeZa avatar Oct 20 '2013 10:10 HuBeZa

Puedes hacerlo:

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

Con estos métodos de extensión:

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

Usar IsMultiple() en el método Duplicates es más rápido que Count() porque no itera toda la colección.

Alex Siepman avatar Aug 31 '2013 13:08 Alex Siepman