C# LINQ 对特定属性的 Distinct()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/489258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
LINQ's Distinct() on a particular property
提问by Patrick Desjardins
I am playing with LINQ to learn about it, but I can't figure out how to use Distinct
when I do not have a simple list (a simple list of integers is pretty easy to do, this is not the question). What I if want to use Distincton a list of an Object on oneor moreproperties of the object?
我正在使用 LINQ 来了解它,但是Distinct
当我没有一个简单的列表时我无法弄清楚如何使用(一个简单的整数列表很容易做到,这不是问题)。如果想在对象的一个或多个属性的对象列表上使用Distinct该怎么办?
Example: If an object is Person
, with Property Id
. How can I get all Person and use Distinct
on them with the property Id
of the object?
示例:如果一个对象是Person
,带有属性Id
。如何获取所有 Person 并使用对象Distinct
的属性在它们上使用Id
?
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
How can I get just Person1
and Person3
? Is that possible?
我怎样才能得到公正Person1
和Person3
?那可能吗?
If it's not possible with LINQ, what would be the best way to have a list of Person
depending on some of its properties in .NET 3.5?
如果 LINQ 无法实现,那么Person
根据 .NET 3.5 中的某些属性获取列表的最佳方法是什么?
采纳答案by Jon Skeet
EDIT: This is now part of MoreLINQ.
编辑:这现在是MoreLINQ 的一部分。
What you need is a "distinct-by" effectively. I don't believe it's part of LINQ as it stands, although it's fairly easy to write:
你需要的是一个有效的“distinct-by”。我不认为它是 LINQ 的一部分,尽管它很容易编写:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
So to find the distinct values using just the Id
property, you could use:
因此,要仅使用该Id
属性查找不同的值,您可以使用:
var query = people.DistinctBy(p => p.Id);
And to use multiple properties, you can use anonymous types, which implement equality appropriately:
要使用多个属性,您可以使用匿名类型,它们适当地实现了相等性:
var query = people.DistinctBy(p => new { p.Id, p.Name });
Untested, but it should work (and it now at least compiles).
未经测试,但它应该可以工作(现在至少可以编译)。
It assumes the default comparer for the keys though - if you want to pass in an equality comparer, just pass it on to the HashSet
constructor.
它假定键的默认比较器 - 如果您想传入相等比较器,只需将其传递给HashSet
构造函数。
回答by mqp
You can do it (albeit not lightning-quickly) like so:
你可以这样做(虽然不是闪电般快速)像这样:
people.Where(p => !people.Any(q => (p != q && p.Id == q.Id)));
That is, "select all people where there isn't another different person in the list with the same ID."
即,“选择列表中没有其他具有相同 ID 的其他人的所有人员”。
Mind you, in your example, that would just select person 3. I'm not sure how to tell which you want, out of the previous two.
请注意,在您的示例中,这只会选择第 3 个人。我不知道如何从前两个中分辨出您想要哪个。
回答by GWLlosa
You should be able to override Equals on person to actually do Equals on Person.id. This ought to result in the behavior you're after.
您应该能够在 person.id 上覆盖 Equals 以实际执行 Equals。这应该会导致您所追求的行为。
回答by Amy B
What if I want to obtain a distinct list based on oneor moreproperties?
如果我想根据一个或多个属性获得一个不同的列表怎么办?
Simple! You want to group them and pick a winner out of the group.
简单的!您想将他们分组并从小组中选出一名获胜者。
List<Person> distinctPeople = allPeople
.GroupBy(p => p.PersonId)
.Select(g => g.First())
.ToList();
If you want to define groups on multiple properties, here's how:
如果要在多个属性上定义组,方法如下:
List<Person> distinctPeople = allPeople
.GroupBy(p => new {p.PersonId, p.FavoriteColor} )
.Select(g => g.First())
.ToList();
回答by Timothy Khouri
I've written an article that explains how to extend the Distinct function so that you can do as follows:
我写了一篇文章,解释了如何扩展 Distinct 函数,以便您可以执行以下操作:
var people = new List<Person>();
people.Add(new Person(1, "a", "b"));
people.Add(new Person(2, "c", "d"));
people.Add(new Person(1, "a", "b"));
foreach (var person in people.Distinct(p => p.ID))
// Do stuff with unique list here.
Here's the article: Extending LINQ - Specifying a Property in the Distinct Function
回答by karcsi
Use:
用:
List<Person> pList = new List<Person>();
/* Fill list */
var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());
The where
helps you filter the entries (could be more complex) and the groupby
and select
perform the distinct function.
将where
帮助你过滤条目(可能更加复杂)和groupby
和select
执行不同的功能。
回答by Chuck Rostance
You could also use query syntax if you want it to look all LINQ-like:
如果您希望它看起来像 LINQ,您也可以使用查询语法:
var uniquePeople = from p in people
group p by new {p.ID} //or group by new {p.ID, p.Name, p.Whatever}
into mygroup
select mygroup.FirstOrDefault();
回答by Contango
The following code is functionally equivalent to Jon Skeet's answer.
以下代码在功能上等同于Jon Skeet 的回答。
Tested on .NET 4.5, should work on any earlier version of LINQ.
在 .NET 4.5 上测试,应该适用于任何早期版本的 LINQ。
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
return source.Where(element => seenKeys.Add(keySelector(element)));
}
Incidentially, check out Jon Skeet's latest version of DistinctBy.cs on Google Code.
回答by Andrzej Gis
In case you need a Distinct method on multiple properties, you can check out my PowerfulExtensionslibrary. Currently it's in a very young stage, but already you can use methods like Distinct, Union, Intersect, Except on any number of properties;
如果您需要在多个属性上使用 Distinct 方法,您可以查看我的强大扩展库。目前它处于非常年轻的阶段,但你已经可以在任意数量的属性上使用 Distinct、Union、Intersect、Except 等方法;
This is how you use it:
这是你如何使用它:
using PowerfulExtensions.Linq;
...
var distinct = myArray.Distinct(x => x.A, x => x.B);
回答by gcoleman0828
The best way to do this that will be compatible with other .NET versions is to override Equals and GetHash to handle this (see Stack Overflow question This code returns distinct values. However, what I want is to return a strongly typed collection as opposed to an anonymous type), but if you need something that is generic throughout your code, the solutions in this article are great.
与其他 .NET 版本兼容的最佳方法是覆盖 Equals 和 GetHash 来处理这个问题(请参阅堆栈溢出问题此代码返回不同的值。但是,我想要的是返回一个强类型集合,而不是匿名类型),但如果您需要在整个代码中通用的东西,本文中的解决方案非常棒。