咨询区
Patrick Desjardins:
我现在正在学习 LINQ,对一个简单类型的 List 进行 Distinct()
是非常简单的,如 List<int>
或 List<string>
,但如果对复杂类型 List<T>
的某一个或者多个属性进行 Distinct() 的话,该如何做呢?
比如下面的 Person 类:
public class Person{public int Id { get; set; }public string Name { get; set; }}
List<Person>
内容如下。
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
现在我如何通过 ID 对 List<Person>
进行去重呢?最终我想要的结果是: person1 和 person3。
回答区
Amy B:
如果你想对 Person 中的一个或者多个属性进行去重,很简单,可以对它们进行分组,然后在每个组上选择一个 赢家 即可。
List<Person> distinctPeople = allPeople.GroupBy(p => p.PersonId).Select(g => g.First()).ToList();
如果基于多个属性进行去重,可以使用 匿名类型
。
List<Person> distinctPeople = allPeople.GroupBy(p => new {p.PersonId, p.FavoriteColor} ).Select(g => g.First()).ToList();
Jon Skeet:
如果你想实现 distinct-by
的效果,其实自己实现一个就可以了,写起来也非常简单。
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;}}
}
有了这个方法后,现在可以根据 Id
属性进行去重了。
var query = people.DistinctBy(p => p.Id);
如果是基于多个属性的话,使用合适的 匿名类型
。
var query = people.DistinctBy(p => new { p.Id, p.Name });
点评区
其实 distinct-by
是一个非常实用的功能,原生的 Linq 不提供支持还是有点可惜的, 我记得以前为了实现此功能还特意让 类
实现 IEquatable 接口实现类型自定义,代码如下:
public class Person : IEquatable<Person>{public int Id { get; set; }public string Name { get; set; }public bool Equals(Person other){throw new NotImplementedException();}}
对了,如果你觉得 Linq 用的不够爽,可以使用第三方的 Linq 扩展版:MoreLinq,官方地址:https://github.com/morelinq/MoreLINQ
原文链接:https://stackoverflow.com/questions/489258/linqs-distinct-on-a-particular-property