我正在玩LINQ来了解它,但是当我没有一个简单的列表时,我无法弄清楚如何使用Distinct(一个简单的整数列表很容易做到,这不是问题).我想在对象的一个或多个属性上使用对象列表中的区别?
示例:如果对象是Person
,则使用Property Id
.如何获取所有Person并使用对象Distinct
的属性Id
?
Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1" Person3: Id=2, Name="Test2"
我怎样才能得到Person1和Person3?那可能吗?
如果LINQ不可能,那么Person
在.NET 3.5 中依赖于某些属性的列表最好的方法是什么?
如果我想根据一个或多个属性获取不同的列表,该怎么办?
简单!你想把它们分组并从小组中挑出一个胜利者.
ListdistinctPeople = allPeople .GroupBy(p => p.PersonId) .Select(g => g.First()) .ToList();
如果要在多个属性上定义组,请按以下步骤操作:
ListdistinctPeople = allPeople .GroupBy(p => new {p.PersonId, p.FavoriteColor} ) .Select(g => g.First()) .ToList();
编辑:这是MoreLINQ的一部分.
你需要的是一个有效的"明显的".我不相信它是LINQ的一部分,尽管写起来相当容易:
public static IEnumerableDistinctBy (this IEnumerable source, Func keySelector) { HashSet seenKeys = new HashSet (); 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 });
未经测试,但它应该工作(现在它至少编译).
它假设键的默认比较器 - 如果要传入相等比较器,只需将其传递给HashSet
构造函数.
如果您希望它看起来像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();
使用:
ListpList = new List (); /* Fill list */ var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());
将where
帮助你过滤条目(可能更加复杂)和groupby
和select
执行不同的功能.
我认为这就足够了:
list.Select(s => s.MyField).Distinct();
首先按字段解决第一组,然后选择firstordefault项.
ListdistinctPeople = allPeople .GroupBy(p => p.PersonId) .Select(g => g.FirstOrDefault()) .ToList();
您可以使用标准执行此操作Linq.ToLookup()
.这将为每个唯一键创建一组值.只需选择集合中的第一个项目即可
Persons.ToLookup(p => p.Id).Select(coll => coll.First());
以下代码在功能上等同于Jon Skeet的答案.
在.NET 4.5上测试,应该适用于任何早期版本的LINQ.
public static IEnumerableDistinctBy ( this IEnumerable source, Func keySelector) { HashSet seenKeys = new HashSet (); return source.Where(element => seenKeys.Add(keySelector(element))); }
最后,查看Jon Skeet在Google Code上的最新版DistinctBy.cs.
我写了一篇文章,解释了如何扩展Distinct函数,以便您可以执行以下操作:
var people = new List(); 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.
这是文章:扩展LINQ - 在不同的函数中指定属性
您可以这样做(尽管不是很快):
people.Where(p => !people.Any(q => (p != q && p.Id == q.Id)));
也就是说,“选择列表中没有其他不同人且具有相同ID的所有人”。
请注意,在您的示例中,您只会选择第3个人。我不确定在前两个中如何辨别您想要哪个。
如果您需要对多个属性使用Distinct方法,可以查看我的PowerfulExtensions库.目前它处于一个非常年轻的阶段,但你已经可以使用Distinct,Union,Intersect等方法,除了任何数量的属性;
这是你如何使用它:
using PowerfulExtensions.Linq; ... var distinct = myArray.Distinct(x => x.A, x => x.B);
当我们在项目中面对这样的任务时,我们定义了一个小的API来构成比较器。
因此,用例是这样的:
var wordComparer = KeyEqualityComparer.Null(). ThenBy(item => item.Text). ThenBy(item => item.LangID); ... source.Select(...).Distinct(wordComparer);
API本身如下所示:
using System; using System.Collections; using System.Collections.Generic; public static class KeyEqualityComparer { public static IEqualityComparerNull () { return null; } public static IEqualityComparer EqualityComparerBy ( this IEnumerable source, Func keyFunc) { return new KeyEqualityComparer (keyFunc); } public static KeyEqualityComparer ThenBy ( this IEqualityComparer equalityComparer, Func keyFunc) { return new KeyEqualityComparer (keyFunc, equalityComparer); } } public struct KeyEqualityComparer : IEqualityComparer { public KeyEqualityComparer( Func keyFunc, IEqualityComparer equalityComparer = null) { KeyFunc = keyFunc; EqualityComparer = equalityComparer; } public bool Equals(T x, T y) { return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) && EqualityComparer .Default.Equals(KeyFunc(x), KeyFunc(y)); } public int GetHashCode(T obj) { var hash = EqualityComparer .Default.GetHashCode(KeyFunc(obj)); if (EqualityComparer != null) { var hash2 = EqualityComparer.GetHashCode(obj); hash ^= (hash2 << 5) + hash2; } return hash; } public readonly Func KeyFunc; public readonly IEqualityComparer EqualityComparer; }
更多详细信息,请访问我们的网站:LINQ中的IEqualityComparer。
我个人使用以下课程:
public class LambdaEqualityComparer: IEqualityComparer { private Func _selector; public LambdaEqualityComparer(Func selector) { _selector = selector; } public bool Equals(TSource obj, TSource other) { return _selector(obj).Equals(_selector(other)); } public int GetHashCode(TSource obj) { return _selector(obj).GetHashCode(); } }
然后,扩展方法:
public static IEnumerableDistinct ( this IEnumerable source, Func selector) { return source.Distinct(new LambdaEqualityComparer (selector)); }
最后,预期用途:
var dates = new List() { /* ... */ } var distinctYears = dates.Distinct(date => date.Year);
我发现使用此方法的优点是将LambdaEqualityComparer
类重新用于接受的其他方法IEqualityComparer
。(哦,我把yield
东西留给了原始的LINQ实现...)
您可以使用DistinctBy()通过对象属性获取Distinct记录。只需在使用前添加以下语句即可:
使用Microsoft.Ajax.Utilities;
然后像下面这样使用它:
var listToReturn = responseList.DistinctBy(x => x.Index).ToList();
其中“索引”是我希望数据与众不同的属性。