Удаление дубликатов в списке с помощью linq
у меня есть класс Items С properties (Id, Name, Code, Price).
список Items заполняется повторяющихся элементов.
например.:
1 Item1 IT00001 0
2 Item2 IT00002 0
3 Item3 IT00003 0
1 Item1 IT00001 0
3 Item3 IT00003 0
Как удалить дубликаты в списке с помощью LINQ?
10 ответов:
var distinctItems = items.Distinct();чтобы сопоставить только некоторые свойства, создайте пользовательский компаратор равенства, например:
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(); } }тогда используйте его так:
var distinctItems = items.Distinct(new DistinctItemComparer());
Если есть что-то, что отбрасывает ваш отдельный запрос, вы можете посмотреть на MoreLinq и используйте оператор DistinctBy и выберите различные объекты по идентификатору.
var distinct = items.DistinctBy( i => i.Id );
вот как я смог сгруппироваться с помощью Linq. Надеюсь, это поможет.
var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());
использовать
Distinct()но имейте в виду, что он использует компаратор равенства по умолчанию для сравнения значений, поэтому, если вы хотите что-то помимо этого, вам нужно реализовать свой собственный компаратор.пожалуйста, смотрите http://msdn.microsoft.com/en-us/library/bb348436.aspx для примера.
у вас есть три варианта здесь для удаления повторяющихся элементов в списке:
- используйте пользовательский компаратор равенства, а затем используйте
Distinct(new DistinctItemComparer())как @Christian Hayter упоминается.использовать
GroupBy, но обратите внимание, вGroupByвы должны группировать по всем столбцам, потому что если вы просто группаIdон не удаляет повторяющиеся элементы всегда. Например, рассмотрим следующий пример: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());результат для этого группировка будет:
{Id = 1, Name = "Item1", Code = "IT00001", Price = 100} {Id = 2, Name = "Item2", Code = "IT00002", Price = 200} {Id = 3, Name = "Item3", Code = "IT00003", Price = 150}что неверно, потому что он считает
{Id = 3, Name = "Item3", Code = "IT00004", Price = 250}как дубликат. Поэтому правильный запрос будет:var distinctItems = a.GroupBy(c => new { c.Id , c.Name , c.Code , c.Price}) .Select(c => c.First()).ToList();3.Переопределить
EqualиGetHashCodeв класс элемента: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(); } }тогда вы можете использовать его следующим образом:
var distinctItems = a.Distinct();
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();
попробуйте этот метод расширения. Надеюсь, это может помочь.
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))); } }использование:
var outputList = sourceList.DistinctBy(x => x.TargetProperty);
универсальный метод расширения:
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()); } }пример использования:
var lstDst = lst.DistinctBy(g => g.Key);
когда вы не хотите писать IEqualityComparer вы можете попробовать что-то вроде следующего.
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; } }
Comments