2009-04-13 30 views
11

对象的名单上有一些对象:鲜明基于任意键LINQ

class Foo { 
    public Guid id; 
    public string description; 
} 

var list = new List<Foo>(); 
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(); 

是否有更好的/更好/更快捷的方式来达到同样的效果。

+0

可能重复的[LINQ的鲜明上的特定属性(http://stackoverflow.com/问题/ 489258/linq-distinct-on-a-particular-property) – zzzzBov 2014-11-25 16:03:22

+0

避免使用字典有很多工作要做。 :) – 2009-04-13 01:49:04

+0

list = list.Distinct(foo => foo.id).ToList();与6行字典解决方案相比大量的工作.... – 2009-04-13 01:56:56

回答

19

一个非常优雅和意图揭示的选择是对的IEnumerable

定义一个新的扩展方法,所以,你必须:

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

而且......

public static IEnumerable<T> Distinct<T,TKey>(this IEnumerable<T> list, Func<T,TKey> lookup) where TKey : struct { 
     return list.Distinct(new StructEqualityComparer<T, TKey>(lookup)); 
    } 


    class StructEqualityComparer<T,TKey> : IEqualityComparer<T> where TKey : struct { 

     Func<T, TKey> lookup; 

     public StructEqualityComparer(Func<T, TKey> 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(); 
     } 
    } 

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

1

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

1
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<Foo>(); 
      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; 
    } 
} 
14

使用Distinct()方法比在我的非正式测试中使用GroupBy()快4倍。对于1百万Foo的测试,我们的测试在大约0.89秒处有Distinct(),以便在GroupBy()大约需要3.4秒的非唯一数组中创建一个唯一阵列。

我非常()调用的样子,

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

FooComparer的样子,

class FooComparer : IEqualityComparer<Foo> { 
    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(); 
1

覆盖的equals(对象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(); 
    } 
} 

然后只需调用鲜明()

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