Eliminar duplicados en la lista usando linq
-
05-07-2019 - |
Pregunta
Tengo un Items
de clase con propiedades (Id, Name, Code, Price)
.
La lista de elementos
se rellena con elementos duplicados.
Por ej .:
1 Item1 IT00001 $100
2 Item2 IT00002 $200
3 Item3 IT00003 $150
1 Item1 IT00001 $100
3 Item3 IT00003 $150
¿Cómo eliminar los duplicados en la lista usando linq?
Solución
var distinctItems = items.Distinct();
Para hacer coincidir solo algunas de las propiedades, crea un comparador de igualdad personalizado, por ejemplo:
class DistinctItemComparer : IEqualityComparer<Item> {
public bool Equals(Item x, Item y) {
return x.Id == y.Id &&
x.Name == y.Name &&
x.Code == y.Code &&
x.Price == y.Price;
}
public int GetHashCode(Item obj) {
return obj.Id.GetHashCode() ^
obj.Name.GetHashCode() ^
obj.Code.GetHashCode() ^
obj.Price.GetHashCode();
}
}
Entonces úsalo así:
var distinctItems = items.Distinct(new DistinctItemComparer());
Otros consejos
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());
Si hay algo que está descartando su consulta de Distinct, puede consultar Haga clic en MoreLinq y use el operador DistinctBy para seleccionar objetos distintos por id.
var distinct = items.DistinctBy( i => i.Id );
Así es como pude agruparme con Linq. Espero que ayude.
var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());
Use Distinct ()
pero tenga en cuenta que utiliza el comparador de igualdad predeterminado para comparar valores, por lo que si desea algo más que eso, necesita implementar su propio comparador.
Consulte http://msdn.microsoft.com/en-us/ library / bb348436.aspx para un ejemplo.
Aquí tiene tres opciones para eliminar un elemento duplicado en su Lista:
- Use un comparador de igualdad personalizado y luego use
Distinct (nuevo DistinctItemComparer ())
como @Christian Hayter mencionado. -
Usa
GroupBy
, pero ten en cuenta que enGroupBy
debes agrupar por todas las columnas porque si solo agrupas porId
no elimina elementos duplicados siempre. Por ejemplo, considere el siguiente ejemplo:List<Item> a = new List<Item> { new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}, new Item {Id = 2, Name = "Item2", Code = "IT00002", Price = 200}, new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}, new Item {Id = 1, Name = "Item1", Code = "IT00001", Price = 100}, new Item {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}, new Item {Id = 3, Name = "Item3", Code = "IT00004", Price = 250} }; var distinctItems = a.GroupBy(x => x.Id).Select(y => y.First());
El resultado de esta agrupación será:
{Id = 1, Name = "Item1", Code = "IT00001", Price = 100} {Id = 2, Name = "Item2", Code = "IT00002", Price = 200} {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}
Lo cual es incorrecto porque considera que
{Id = 3, Name = " Item3 " ;, Code = " IT00004 " ;, Price = 250}
como duplicado. Así que la consulta correcta sería:var distinctItems = a.GroupBy(c => new { c.Id , c.Name , c.Code , c.Price}) .Select(c => c.First()).ToList();
3.Override
Equal
yGetHashCode
en la clase de elemento:public class Item { public int Id { get; set; } public string Name { get; set; } public string Code { get; set; } public int Price { get; set; } public override bool Equals(object obj) { if (!(obj is Item)) return false; Item p = (Item)obj; return (p.Id == Id && p.Name == Name && p.Code == Code && p.Price == Price); } public override int GetHashCode() { return String.Format("{0}|{1}|{2}|{3}", Id, Name, Code, Price).GetHashCode(); } }
Entonces puedes usarlo así:
var distinctItems = a.Distinct();
Un método de extensión universal:
public static class EnumerableExtensions
{
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector)
{
return enumerable.GroupBy(keySelector).Select(grp => grp.First());
}
}
Ejemplo de uso:
var lstDst = lst.DistinctBy(item => item.Key);
List<Employee> employees = new List<Employee>()
{
new Employee{Id =1,Name="AAAAA"}
, new Employee{Id =2,Name="BBBBB"}
, new Employee{Id =3,Name="AAAAA"}
, new Employee{Id =4,Name="CCCCC"}
, new Employee{Id =5,Name="AAAAA"}
};
List<Employee> duplicateEmployees = employees.Except(employees.GroupBy(i => i.Name)
.Select(ss => ss.FirstOrDefault()))
.ToList();
Prueba este método de extensión. Esperemos que esto pueda ayudar.
public static class DistinctHelper
{
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
var identifiedKeys = new HashSet<TKey>();
return source.Where(element => identifiedKeys.Add(keySelector(element)));
}
}
Uso:
var outputList = sourceList.DistinctBy(x => x.TargetProperty);
Cuando no quieras escribir IEqualityComparer, puedes intentar algo como lo siguiente.
class Program
{
private static void Main(string[] args)
{
var items = new List<Item>();
items.Add(new Item {Id = 1, Name = "Item1"});
items.Add(new Item {Id = 2, Name = "Item2"});
items.Add(new Item {Id = 3, Name = "Item3"});
//Duplicate item
items.Add(new Item {Id = 4, Name = "Item4"});
//Duplicate item
items.Add(new Item {Id = 2, Name = "Item2"});
items.Add(new Item {Id = 3, Name = "Item3"});
var res = items.Select(i => new {i.Id, i.Name})
.Distinct().Select(x => new Item {Id = x.Id, Name = x.Name}).ToList();
// now res contains distinct records
}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}