Как найти и удалить дубликаты объектов в коллекции с помощью LINQ?

У меня есть простой класс, представляющий объект. Он имеет 5 свойств (дата, 2 десятичных знака, целое число и строка). У меня есть класс коллекции, полученный из CollectionBase, который является классом контейнера для хранения нескольких объектов из моего первого класса.

Мой вопрос: я хочу удалить повторяющиеся объекты (например, объекты с одинаковой датой, одинаковые десятичные числа, одинаковые целые числа и одна и та же строка). Есть ли запрос LINQ, который я могу написать, чтобы найти и удалить дубликаты? Или найти их как минимум?

Ответ 1

Вы можете удалить дубликаты с помощью оператора Distinct.

Есть две перегрузки - для вашего типа используется сопоставитель равенства по умолчанию (который для настраиваемого типа будет вызывать метод Equals() для типа). Второй позволяет вам предоставить свой собственный аналог равенства. Они оба возвращают новую последовательность, представляющую ваш исходный набор без дубликатов. Ни одна перегрузка на самом деле не изменяет вашу первоначальную коллекцию - они оба возвращают новую последовательность, исключающую дубликаты..

Если вы хотите просто найти дубликаты, вы можете использовать GroupBy для этого:

var groupsWithDups = list.GroupBy( x => new { A = x.A, B = x.B, ... }, x => x ) 
                         .Where( g => g.Count() > 1 );

Чтобы удалить дубликаты из чего-то вроде IList<>, вы можете сделать:

yourList.RemoveAll( yourList.Except( yourList.Distinct() ) );

Ответ 2

Если ваш простой класс использует Equals таким образом, который удовлетворяет вашим требованиям, вы можете использовать метод Distinct

var col = ...;
var noDupes = col.Distinct();

Если нет, вам нужно предоставить экземпляр IEqualityComparer<T>, который сравнивает значения так, как вы пожелаете. Например (нулевые проблемы игнорируются для краткости)

public class MyTypeComparer : IEqualityComparer<MyType> {
  public bool Equals(MyType left, MyType right) {
    return left.Name == right.Name;
  }
  public int GetHashCode(MyType type) {
    return 42;
  }
}

var noDupes = col.Distinct(new MyTypeComparer());

Обратите внимание, что использование константы для GetHashCode является преднамеренным. Не зная подробных сведений о семантике MyType, невозможно написать эффективную и правильную хэширующую функцию. Вместо эффективной функции хэширования я использовал константу, которая правильна независимо от семантики этого типа.