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

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

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


person Icemanind    schedule 13.07.2010    source источник


Ответы (2)


Вы можете удалить дубликаты с помощью оператора 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() ) );
person LBushkin    schedule 13.07.2010
comment
Это удалит их из моей коллекции или только из запроса LINQ? - person Icemanind; 13.07.2010
comment
Методы расширения LINQ создают новые наборы элементов, ваша исходная коллекция останется нетронутой. - person Matthew Abbott; 13.07.2010

Если ваш простой класс использует 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, невозможно написать эффективную и правильную функцию хеширования. Вместо эффективной хэш-функции я использовал константу, которая корректна независимо от семантики типа.

person JaredPar    schedule 13.07.2010
comment
Удалит ли это их из моей коллекции? Или просто запрос LINQ? - person Icemanind; 13.07.2010
comment
@icemanind вернет новую коллекцию, в которой нет дубликатов. Он не изменит коллекцию на месте. - person JaredPar; 13.07.2010
comment
Отличный и лучший практический ответ - person danielea; 25.08.2014