基于LINQ中任意键的不同对象列表

我有一些对象:

class Foo { public Guid id; public string description; } var list = new List(); list.Add(new Foo() { id = Guid.Empty, description = "empty" }); list.Add(new Foo() { id = Guid.Empty, description = "empty" }); list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty" }); list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty2" }); 

我想以这样的方式处理这个列表: id字段是唯一的,并抛弃非唯一对象(基于id)。

我能想到的最好的是:

 list = list.GroupBy(i => i.id).Select(g=>g.First()).ToList(); 

是否有更好/更好/更快的方法来实现相同的结果。

一个非常优雅和意图揭示的选项是在IEnumerable上定义一个新的扩展方法

所以你有了:

 list = list.Distinct(foo => foo.id).ToList(); 

而……

  public static IEnumerable Distinct(this IEnumerable list, Func lookup) where TKey : struct { return list.Distinct(new StructEqualityComparer(lookup)); } class StructEqualityComparer : IEqualityComparer where TKey : struct { Func lookup; public StructEqualityComparer(Func lookup) { this.lookup = lookup; } public bool Equals(T x, T y) { return lookup(x).Equals(lookup(y)); } public int GetHashCode(T obj) { return lookup(obj).GetHashCode(); } } 

可以构建类似的辅助类来比较对象。 (它需要做更好的空值处理)

在我的非正式测试中,使用Distinct()方法比使用GroupBy()快4倍。 对于100万Foo,我的测试在大约0.89秒内有Distinct(),以便在一个非独特arrays中创建一个独特的arrays,其中GroupBy()大约需要3.4秒。

我的Distinct()调用看起来像,

 var unique = list.Distinct(FooComparer.Instance).ToArray(); 

FooComparer看起来像,

 class FooComparer : IEqualityComparer { public static readonly FooComparer Instance = new FooComparer(); public bool Equals(Foo x, Foo y) { return x.id.Equals(y.id); } public int GetHashCode(Foo obj) { return obj.id.GetHashCode(); } } 

和我的GroupBy()版本看起来像,

 var unique = (from l in list group l by l.id into g select g.First()).ToArray(); 

创建一个IEqualityComparer ,如果id字段相同则返回true,并将其传递给Distinct()运算符。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var list = new List(); list.Add(new Foo() { id = Guid.Empty, description = "empty" }); list.Add(new Foo() { id = Guid.Empty, description = "empty" }); list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty" }); list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty2" }); var unique = from l in list group l by new { l.id, l.description } into g select g.Key; foreach (var f in unique) Console.WriteLine("ID={0} Description={1}", f.id,f.description); Console.ReadKey(); } } class Foo { public Guid id; public string description; } } 

覆盖Equals(object obj)GetHashCode()方法:

 class Foo { public readonly Guid id; public string description; public override bool Equals(object obj) { return ((Foo)obj).id == id; } public override int GetHashCode() { return id.GetHashCode(); } } 

然后只需调用Distinct()

 list = list.Distinct().ToList();