Правильно, поэтому у меня есть перечислимое и я хочу получить от него различные значения.
Используя System.Linq
, конечно, есть метод расширения под названием Distinct
. В простом случае его можно использовать без параметров, например:
var distinctValues = myStringList.Distinct();
Хорошо, но если у меня есть множество объектов, для которых мне нужно указать равенство, единственная доступная перегрузка:
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
Аргумент сравнения равенства должен быть экземпляром IEqualityComparer<T>
. Я могу сделать это, конечно, но это несколько многословно и, ну, в общем, грязно.
То, что я ожидал бы, является перегрузкой, которая взяла бы лямбду, скажем Func <T, T, bool>:
var distinctValues
= myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
Кто-нибудь знает, существует ли какое-то такое расширение или какой-то эквивалентный обходной путь? Или я что-то упустил?
В качестве альтернативы, есть ли способ указания встроенного IEqualityComparer (смущать меня)?
Обновить
Я нашел ответ Андерса Хейлсберга на пост на форуме MSDN на эту тему. Он говорит:
Проблема, с которой вы столкнетесь, состоит в том, что, когда два объекта сравниваются одинаково, они должны иметь одинаковое возвращаемое значение GetHashCode (иначе хеш-таблица, используемая внутри Distinct, не будет работать правильно). Мы используем IEqualityComparer, потому что он упаковывает совместимые реализации Equals и GetHashCode в единый интерфейс.
Я полагаю, это имеет смысл ..
источник
.Distinct(new KeyEqualityComparer<Customer,string>(c1 => c1.CustomerId))
, и объяснить , почему GetHashCode () имеет важное значение для правильной работы.Ответы:
источник
DistinctBy
(или дажеDistinct
, поскольку подпись будет уникальной).yield
оператор, поэтому потоковая передача технически невозможна. Спасибо за ваш ответ, хотя. Я буду использовать его при кодировании в C #. ;-)Мне кажется, что ты хочешь
DistinctBy
от MoreLINQ . Вы можете написать:Вот урезанная версия
DistinctBy
(без проверки недействительности и без возможности указать свой собственный ключ сравнения):источник
yield
+ extra lib, foreach может быть переписан какreturn source.Where(element => knownKeys.Add(keySelector(element)));
Обернуть вещи . Я думаю, что большинство людей, которые пришли сюда, как я, хотят простейшего решения без использования каких-либо библиотек и с максимально возможной производительностью .
(Принятая группа по методу для меня, я думаю, является излишним с точки зрения производительности.)
Вот простой метод расширения, использующий интерфейс IEqualityComparer, который работает также для нулевых значений.
Применение:
Код метода расширения
источник
Нет, такой перегрузки метода расширения для этого нет. Я находил это разочаровывающим в прошлом и поэтому обычно пишу вспомогательный класс для решения этой проблемы. Цель состоит в том, чтобы преобразовать
Func<T,T,bool>
вIEqualityComparer<T,T>
.пример
Это позволяет вам написать следующее
источник
IEqualityComparer<T>
из проекции: stackoverflow.com/questions/188120/…Сокращенное решение
источник
Это будет делать то, что вы хотите, но я не знаю о производительности:
По крайней мере, это не многословно.
источник
Вот простой метод расширения, который делает то, что мне нужно ...
Жаль, что они не внедрили какой-то особый метод в рамки, но эй хо.
источник
x.Key
чтобыx.First()
и изменить возвращаемое значениеIEnumerable<T>
Что-то, что я использовал, и это хорошо для меня.
источник
Все решения, которые я видел здесь, основаны на выборе уже сопоставимого поля. Однако, если нужно сравнивать по-другому, то здесь это решение, как правило, работает для чего-то вроде:
источник
Возьми другой путь:
Последовательность, возвращающая различные элементы, сравнивает их по свойству _myCaustomerProperty.
источник
Вы можете использовать InlineComparer
Образец использования :
Источник: https://stackoverflow.com/a/5969691/206730
Использование IEqualityComparer для Union
Могу ли я указать свой явный компаратор типа inline?
источник
Вы можете использовать LambdaEqualityComparer:
источник
Хитрый способ сделать это - использовать
Aggregate()
расширение, используя словарь в качестве аккумулятора со значениями свойства ключа в качестве ключей:И решение в стиле GroupBy использует
ToLookup()
:источник
Dictionary<int, Customer>
вместо этого?Я предполагаю, что у вас есть IEnumerable, и в вашем примере делегата вы хотели бы, чтобы c1 и c2 ссылались на два элемента в этом списке?
Я полагаю, что вы могли бы достичь этого с помощью самостоятельного объединения var varResults = from c1 в myList join c2 в myList on
источник
Если
Distinct()
не дает уникальных результатов, попробуйте это:источник
В пакете Microsoft System.Interactive имеется версия Distinct, в которой используется лямбда-ключ выбора. По сути, это то же самое, что и решение Джона Скита, но оно может помочь людям узнать и проверить остальную часть библиотеки.
источник
Вот как вы можете это сделать:
Этот метод позволяет вам использовать его, указав один параметр как
.MyDistinct(d => d.Name)
, но он также позволяет вам указывать наличие условия в качестве второго параметра, например, так:NB. Это также позволит вам указать другие функции, например, например
.LastOrDefault(...)
.Если вы хотите показать только условие, вы можете сделать его еще проще, реализовав его следующим образом:
В этом случае запрос будет выглядеть так:
NB. Здесь выражение проще, но примечание
.MyDistinct2
использует.FirstOrDefault(...)
неявно.Примечание. В приведенных выше примерах используется следующий демонстрационный класс.
источник
IEnumerable
лямбда-расширение:Применение:
источник