我正在使用LINQ进行学习,可是当我没有简单的列表时(我很容易作到简单的整数列表,这不是问题),我没法弄清楚如何使用Distinct。 若是要在对象的一个或多个属性的对象列表上使用Distinct ,该怎么办? web
示例:若是一个对象是Person
,具备Property Id
。 如何获取全部Person并在其上使用Distinct
和对象的属性Id
? 学习
Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1" Person3: Id=2, Name="Test2"
我怎样才能获得Person1和Person3? 那可能吗? 测试
若是LINQ没法实现,那么根据.NET 3.5中Person
某些属性来获取Person
列表的最佳方法是什么? 网站
如下代码在功能上等同于Jon Skeet的答案 。 this
在.NET 4.5上进行了测试,能够在任何早期版本的LINQ上运行。 google
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))); }
偶然地, 在Google Code上查看Jon Skeet的DistinctBy.cs最新版本 。 spa
若是须要在多个属性上使用Distinct方法,则能够签出个人PowerfulExtensions库。 当前它还处于起步阶段,可是您已经能够在许多属性上使用Distinct,Union,Intersect,Except等方法。 code
这是您的用法: 对象
using PowerfulExtensions.Linq; ... var distinct = myArray.Distinct(x => x.A, x => x.B);
与其余.NET版本兼容的最佳方法是重写Equals和GetHash来处理此问题(请参阅Stack Overflow问题。 此代码返回不一样的值。可是,我要返回的是强类型集合,而不是匿名类型 ),可是若是您须要在整个代码中使用通用的东西,那么本文中的解决方案很是有用。 blog
当咱们在项目中面对这样的任务时,咱们定义了一个小的API来构成比较器。
所以,用例是这样的:
var wordComparer = KeyEqualityComparer.Null<Word>(). 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 IEqualityComparer<T> Null<T>() { return null; } public static IEqualityComparer<T> EqualityComparerBy<T, K>( this IEnumerable<T> source, Func<T, K> keyFunc) { return new KeyEqualityComparer<T, K>(keyFunc); } public static KeyEqualityComparer<T, K> ThenBy<T, K>( this IEqualityComparer<T> equalityComparer, Func<T, K> keyFunc) { return new KeyEqualityComparer<T, K>(keyFunc, equalityComparer); } } public struct KeyEqualityComparer<T, K>: IEqualityComparer<T> { public KeyEqualityComparer( Func<T, K> keyFunc, IEqualityComparer<T> equalityComparer = null) { KeyFunc = keyFunc; EqualityComparer = equalityComparer; } public bool Equals(T x, T y) { return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) && EqualityComparer<K>.Default.Equals(KeyFunc(x), KeyFunc(y)); } public int GetHashCode(T obj) { var hash = EqualityComparer<K>.Default.GetHashCode(KeyFunc(obj)); if (EqualityComparer != null) { var hash2 = EqualityComparer.GetHashCode(obj); hash ^= (hash2 << 5) + hash2; } return hash; } public readonly Func<T, K> KeyFunc; public readonly IEqualityComparer<T> EqualityComparer; }
更多详细信息,请访问咱们的网站: LINQ中的IEqualityComparer 。
您可使用标准的Linq.ToLookup()
。 这将为每一个惟一键建立一个值集合。 只需选择集合中的第一项
Persons.ToLookup(p => p.Id).Select(coll => coll.First());