Удалить дубликаты в списке, используя linq
У меня есть класс Items
с properties (Id, Name, Code, Price)
.
Список Items
заполняется дублируемыми элементами.
Например:
1 Item1 IT00001 $100
2 Item2 IT00002 $200
3 Item3 IT00003 $150
1 Item1 IT00001 $100
3 Item3 IT00003 $150
Как удалить дубликаты в списке с помощью linq?
Ответы
Ответ 1
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());
Ответ 2
var distinctItems = items.GroupBy(x => x.Id).Select(y => y.First());
Ответ 3
Если есть что-то, что отбрасывает ваш Distinct-запрос, вы можете посмотреть MoreLinq и использовать оператор DistinctBy и выбрать отдельные объекты по id.
var distinct = items.DistinctBy( i => i.Id );
Ответ 4
Вот как я смог сгруппировать с Linq. Надеюсь, что это поможет.
var query = collection.GroupBy(x => x.title).Select(y => y.FirstOrDefault());
Ответ 5
Используйте Distinct()
, но имейте в виду, что он использует сопоставитель по умолчанию для сравнения значений, поэтому, если вам нужно что-либо помимо этого, вам нужно реализовать свой собственный компаратор.
Для примера см. http://msdn.microsoft.com/en-us/library/bb348436.aspx.
Ответ 6
У вас есть три варианта удаления дубликата в списке:
- Используйте собственный сопоставитель сравнений, а затем используйте
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();
Ответ 7
Универсальный метод расширения:
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(item => item.Key);
Ответ 8
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();
Ответ 9
Попробуйте использовать этот метод расширения. Надеюсь, это может помочь.
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);
Ответ 10
Если вы не хотите писать 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; }
}