C# LINQ encuentra duplicados en la lista
Usando LINQ, desde a List<int>
, ¿cómo puedo recuperar una lista que contiene entradas repetidas más de una vez y sus valores?
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 List
tipo anónimo y cada elemento tendrá las propiedades Element
y Counter
para 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.
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);
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};
GroupBy
agrupará 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};
GroupBy
agrupará 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.
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);
}
}
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.