linq - una - contar valores repetidos en un array c#
C#LINQ encuentra duplicados en la lista (7)
Utilizando LINQ, de una List<int>
, ¿cómo puedo recuperar una lista que contiene entradas repetidas más de una vez y sus valores?
Averigüe si un enumerable contiene cualquier duplicado :
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
Averigüe si todos los valores enumerables son únicos :
var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);
Conjunto completo de extensiones de Linq a SQL de las funciones de Duplicados verificadas en MS SQL Server. Sin usar .ToList () o IEnumerable. Estas consultas se ejecutan en SQL Server en lugar de en la memoria. . Los resultados solo regresan a la memoria.
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()));
}
Creé una extensión para responder a esto. Podrías incluirlo en tus proyectos. Creo que esto es lo más importante cuando buscas duplicados en Lista o Linq.
Ejemplo:
//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
*/
}
La forma más fácil 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 usar:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Element = y.Key, Counter = y.Count() })
.ToList();
Esto devolverá una List
de un tipo anónimo, y cada elemento tendrá las propiedades Element
y Counter
para recuperar la información que necesita.
Y por último, si es un diccionario lo que busca, puede usar
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 repita como valor.
Otra forma es usando 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)).ToList().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 de Duplicados es más rápido que Count () porque esto no itera toda la colección.
Para encontrar los valores duplicados solamente:
var duplicates = list.GroupBy(x => x.Key).Any(g => g.Count() > 1);
P.ej. lista de var = nuevo [] {1,2,3,1,4,2};
por lo tanto, agrupar por agrupará los números por sus claves y mantendrá el conteo (el número de veces que se repitió) con él. Después de eso, solo estamos comprobando los valores que han repetido más de una vez.
Para encontrar los valores únicos únicamente:
var unique = list.GroupBy(x => x.Key).All(g => g.Count() == 1);
P.ej. lista de var = nuevo [] {1,2,3,1,4,2};
por lo tanto, agrupar por agrupará los números por sus claves y mantendrá el conteo (el número de veces que se repitió) con él. Después de eso, solo verificamos los valores que han repetido solo una vez que los medios son únicos.