2009-04-13 29 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();