Я играю с LINQ, чтобы узнать об этом, но я не могу понять, как использовать, Distinct
когда у меня нет простого списка (простой список целых чисел довольно прост, это не вопрос). Что мне делать, если я хочу использовать Distinct в списке объектов в одном или нескольких свойствах объекта?
Пример: если объект есть Person
, со свойством Id
. Как я могу получить все лица и использовать Distinct
их со свойством Id
объекта?
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
Как я могу получить только Person1
и Person3
? Это возможно?
Если это невозможно с LINQ, что будет лучшим способом иметь список в Person
зависимости от некоторых его свойств в .NET 3.5?
GroupBy
проще. Если вам это нужно в более чем одном месте, гораздо лучше (IMO) инкапсулировать намерение.IQueryable<T>
, я не понимаю, насколько это актуально. Я согласен, что это не подходит для EF и т. Д., Но в LINQ to Objects я думаю, что это больше подходит, чемGroupBy
. Контекст вопроса всегда важен.Просто! Вы хотите сгруппировать их и выбрать победителя из группы.
Если вы хотите определить группы для нескольких свойств, вот как:
источник
Single()
иSingleOrDefault()
каждый бросок, когда у источника более одного предмета. В этой операции мы ожидаем, что каждая группа может иметь более одного элемента. В этом отношенииFirst()
предпочтительнее,FirstOrDefault()
потому что в каждой группе должен быть хотя бы один член .... если только вы не используете EntityFramework, который не может понять, что в каждой группе есть хотя бы один член и требованияFirstOrDefault()
.FirstOrDefault()
github.com/dotnet/efcore/issues/12088. Я использую 3.1 и получаю сообщения об «невозможности перевода».Использование:
where
Позволяет фильтровать записи (может быть более сложным) , аgroupby
иselect
выполняют определенную функцию.источник
Вы также можете использовать синтаксис запроса, если хотите, чтобы он выглядел как LINQ:
источник
Я думаю этого достаточно
источник
Решение сначала сгруппируйте по полям, затем выберите элемент firstordefault.
источник
Вы можете сделать это с помощью стандарта
Linq.ToLookup()
. Это создаст коллекцию значений для каждого уникального ключа. Просто выберите первый элемент в коллекцииисточник
Следующий код функционально эквивалентен ответу Джона Скита .
Протестировано на .NET 4.5, должно работать на любой более ранней версии LINQ.
Кстати, посмотрите последнюю версию DistinctBy.cs Джона Скита в Google Code .
источник
Я написал статью, в которой объясняется, как расширить функцию Distinct, чтобы вы могли сделать следующее:
Вот статья: Расширение LINQ - Указание свойства в отдельной функции
источник
Лично я использую следующий класс:
Затем метод расширения:
Наконец, предполагаемое использование:
Преимущество, которое я нашел, используя этот подход, заключается в повторном использовании
LambdaEqualityComparer
класса для других методов, которые принимаютIEqualityComparer
. (О, и я оставляюyield
материал для оригинальной реализации LINQ ...)источник
Если вам нужен метод Distinct для нескольких свойств, вы можете проверить мою библиотеку PowerfulExtensions . В настоящее время он находится на очень молодой стадии, но уже вы можете использовать такие методы, как Distinct, Union, Intersect, Except, для любого количества свойств;
Вот как вы используете это:
источник
Когда мы столкнулись с такой задачей в нашем проекте, мы определили небольшой API для составления компараторов.
Итак, вариант использования был такой:
И сам API выглядит так:
Более подробная информация на нашем сайте: IEqualityComparer в LINQ .
источник
Вы можете использовать DistinctBy () для получения записей Distinct по свойству объекта. Просто добавьте следующее утверждение перед его использованием:
и затем используйте его следующим образом:
где «Индекс» - это свойство, для которого я хочу, чтобы данные были различны.
источник
Вы можете сделать это (хотя и не молниеносно) так:
То есть «выбрать всех людей, у которых в списке нет другого человека с таким же идентификатором».
Имейте в виду, в вашем примере это просто выберет человека 3. Я не уверен, как сказать, что вы хотите, из двух предыдущих.
источник
Если вы не хотите добавлять библиотеку MoreLinq в свой проект просто для того, чтобы получить
DistinctBy
функциональность, вы можете получить тот же конечный результат, используя перегрузку метода Linq,Distinct
которая принимаетIEqualityComparer
аргумент.Вы начинаете с создания универсального пользовательского класса сравнения равенств, который использует лямбда-синтаксис для выполнения пользовательского сравнения двух экземпляров универсального класса:
Тогда в вашем основном коде вы используете его так:
Вуаля! :)
Вышесказанное предполагает следующее:
Person.Id
типаint
people
Коллекция не содержит каких - либо элементов неопределенныеЕсли коллекция может содержать нули, просто перепишите лямбда-выражения для проверки на ноль, например:
РЕДАКТИРОВАТЬ
Этот подход похож на ответ в ответе Владимира Нестеровского, но проще.
Это также похоже на ответ в ответе Джоэла, но допускает сложную логику сравнения, включающую несколько свойств.
Однако, если ваши объекты могут только когда-либо отличаться,
Id
другой пользователь дал правильный ответ, что все, что вам нужно сделать, это переопределить реализации по умолчаниюGetHashCode()
иEquals()
в вашемPerson
классе, а затем просто использоватьDistinct()
готовый метод Linq для фильтрации любые дубликаты.источник
Лучший способ сделать это совместимым с другими версиями .NET - переопределить Equals и GetHash, чтобы справиться с этим (см. Вопрос переполнения стека. Этот код возвращает различные значения. Однако я хочу вернуть строго типизированную коллекцию, а не анонимный тип ), но если вам нужно что-то общее в вашем коде, решения в этой статье будут хорошими.
источник
источник
Select()
new Person
вместоnew Player
? Тот факт, что вы заказываете поID
, не каким-то образом информируетDistinct()
об использовании этого свойства при определении уникальности, поэтому это не сработает.Переопределите методы Equals (object obj) и GetHashCode () :
а затем просто позвоните:
источник
Вы должны иметь возможность переопределить Equals для человека, чтобы фактически сделать Equals для Person.id. Это должно привести к поведению, которое вы преследуете.
источник
Пожалуйста, попробуйте с кодом ниже.
источник