Usando LINQ, desde a List<int>
, ¿cómo puedo recuperar una lista que contiene entradas repetidas más de una vez y sus valores?
Usando LINQ, desde a List<int>
, ¿cómo puedo recuperar una lista que contiene entradas repetidas más de una vez y sus valores?
Respuestas:
La forma más fácil de resolver el problema es agrupar los elementos en función de 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 desea saber cuántas veces se repiten los elementos, puede usar:
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 está buscando un diccionario, 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 la cantidad de veces que se repite como valor.
code
for (int i = 0; i <duplicates.Count; i ++) {int duplicate = duplicates [i]; duplicatesLocation.Add (duplicado, nueva Lista <int> ()); for (int k = 0; k <hitsList.Length; k ++) {if (hitsList [k] .Contains (duplicate)) {duplicatesLocation.ElementAt (i) .Value.Add (k); }} // eliminar duplicados de acuerdo con algunas reglas. }code
Averigüe si un enumerable contiene algún duplicado :
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
Averigüe si todos los valores en un enumerable son únicos :
var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);
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);
}
}
List<int> { 1, 2, 3, 4, 5, 2 }
como fuente, el resultado es un IEnumerable<int>
elemento con un valor de 1
(donde el valor duplicado correcto es 2)
Console.WriteLine("Count: {0}", duplicates.Count());
directamente debajo e imprime 6
. A menos que me falte algo sobre los requisitos para esta función, solo debe haber 1 elemento en la colección resultante.
ToList
para solucionar el problema, pero significa que el método se ejecuta tan pronto como se lo llamó, y no cuando iteras sobre los resultados.
var hash = new HashSet<int>();
var duplicates = list.Where(i => !hash.Add(i));
conducirá a una lista que incluye todas las ocurrencias de duplicados. Entonces, si tiene cuatro ocurrencias de 2 en su lista, entonces su lista duplicada contendrá tres ocurrencias de 2, ya que solo una de las 2 se puede agregar al HashSet. Si desea que su lista contenga valores únicos para cada duplicado, use este código en su lugar:var duplicates = mylist.Where(item => !myhash.Add(item)).ToList().Distinct().ToList();
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 Duplicados es más rápido que Count () porque esto no itera toda la colección.
Count()
está precalculada y que su solución es más lenta.
Count()
] es básicamente diferente de iterar toda la lista. Count()
está precalculado pero no lo está iterando toda la lista.
Creé una extensión para responder a esto, podría incluirlo en sus proyectos, creo que esto devuelve la mayoría de los casos cuando busca duplicados en List 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
*/
}
Para buscar solo los valores duplicados:
var duplicates = list.GroupBy(x => x.Key).Any(g => g.Count() > 1);
P.ej. var list = new [] {1,2,3,1,4,2};
entonces group by agrupará los números por sus teclas y mantendrá la cuenta (número de veces que se repitió) con él. Después de eso, solo estamos verificando los valores que se han repetido más de una vez.
Para encontrar solo los valores únicos:
var unique = list.GroupBy(x => x.Key).All(g => g.Count() == 1);
P.ej. var list = new [] {1,2,3,1,4,2};
entonces group by agrupará los números por sus teclas y mantendrá la cuenta (número de veces que se repitió) con él. Después de eso, solo estamos verificando los valores que han repetido solo una vez que los medios son únicos.
var unique = list.Distinct(x => x)
Conjunto completo de extensiones de Linq a SQL de funciones duplicadas marcadas en MS SQL Server. Sin usar .ToList () o IEnumerable. Estas consultas se ejecutan en SQL Server en lugar de en memoria. . Los resultados solo vuelven 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()));
}
hay una respuesta pero no entendí por qué no funciona;
var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);
mi solución es así en esta situación;
var duplicates = model.list
.GroupBy(s => s.SAME_ID)
.Where(g => g.Count() > 1).Count() > 0;
if(duplicates) {
doSomething();
}