我正在玩LINQ来了解它,但是当我没有一个简单的列表时,我无法弄清楚如何使用Distinct(一个简单的整数列表很容易做到,这不是问题) . 我想在对象的一个或多个属性上的Object列表中使用Distinct的内容是什么?
示例:如果对象为 Person
,则为Property Id
. 如何获取所有Person并使用对象的属性 Id
对它们使用 Distinct
?
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
我怎样才能得到Person1和Person3?那可能吗?
如果LINQ不可能,那么根据.NET 3.5中的某些属性获得 Person
列表的最佳方法是什么?
19 回答
使用:
where
帮助您过滤条目(可能更复杂),groupby
和select
执行不同的功能 .首先按字段解决第一组,然后选择firstordefault项目 .
简单!你想把它们分组并从小组中挑出一个胜利者 .
如果要在多个属性上定义组,请按以下步骤操作:
以下代码在功能上等同于Jon Skeet's answer .
在.NET 4.5上测试,应该适用于任何早期版本的LINQ .
一般情况下,请查看Jon Skeet's latest version of DistinctBy.cs on Google Code .
您应该能够在人员上覆盖Equals以实际在Person.id上执行Equals . 这应该导致你所追求的行为 .
您可以使用标准Linq.ToLookup()执行此操作 . 这将为每个唯一键创建一组值 . 只需选择集合中的第一个项目即可
与其他.NET版本兼容的最佳方法是重写Equals和GetHash来处理这个问题(请参阅Stack Overflow问题This code returns distinct values. However, what I want is to return a strongly typed collection as opposed to an anonymous type),但如果您需要在整个代码中使用通用的东西,那么本文中的解决方案是大 .
我认为这就足够了:
我个人使用以下类:
然后,扩展方法:
最后,预期用途:
我发现使用这种方法的优点是重新使用
LambdaEqualityComparer
类用于接受IEqualityComparer
的其他方法 . (哦,我把yield
的东西留给原来的LINQ实现......)如果您希望它看起来像LINQ一样,您也可以使用查询语法:
如果您需要对多个属性使用Distinct方法,可以查看我的PowerfulExtensions库 . 目前它处于一个非常年轻的阶段,但你已经可以使用Distinct,Union,Intersect等方法,除了任何数量的属性;
这是你如何使用它:
EDIT :现在是MoreLINQ的一部分 .
你需要的是一个有效的“明显的” . 我不相信它是LINQ的一部分,尽管它写起来相当容易:
因此,要仅使用
Id
属性查找不同的值,您可以使用:要使用多个属性,可以使用匿名类型,它们适当地实现相等:
未经测试,但它应该工作(现在它至少编译) .
它假设键的默认比较器 - 如果要传入相等比较器,只需将其传递给
HashSet
构造函数 .当我们在项目中遇到这样的任务时,我们定义了一个小的API来组成比较器 .
所以,用例是这样的:
API本身看起来像这样:
更多详情请访问我们的网站:IEqualityComparer in LINQ .
我写了一篇文章,解释了如何扩展Distinct函数,以便您可以执行以下操作:
这是文章:Extending LINQ - Specifying a Property in the Distinct Function
如果您不想将MoreLinq库添加到项目中以获取
DistinctBy
功能,那么您可以使用Linq的Distinct
方法的重载获取相同的最终结果,该方法接收IEqualityComparer
参数 .首先,创建一个通用的自定义相等比较器类,它使用lambda语法来执行泛型类的两个实例的自定义比较:
然后在你的主代码中使用它如下:
瞧! :)
以上假设如下:
属性
Person.Id
的类型为int
people
集合不包含任何null元素如果集合可以包含空值,那么只需重写lambdas以检查null,例如:
EDIT
这种方法类似于Vladimir Nesterovsky的答案,但更简单 .
它也与Joel的答案类似,但允许涉及多个属性的复杂比较逻辑 .
但是,如果您的对象只能因
Id
而异,那么另一个用户给出了正确的答案,您需要做的就是覆盖Person
类中GetHashCode()
和Equals()
的默认实现,然后只使用开箱即用的Distinct()
Linq to . 的方法过滤掉任何重复项 .请试试下面的代码 .
覆盖 Equals(object obj) 和 GetHashCode() 方法:
然后打电话:
你可以这样做(尽管不是闪电般快速):
也就是说,“选择列表中没有其他不同人的所有人使用相同的ID . ”
在你的例子中,请注意,只选择人3.我不知道如何分辨出你想要的东西,而不是前两个 .