2014-03-13 19 views
1

我想寫一個複雜類型的集合的LINQ查詢。我想在兩個字段的組合上爲這個集合寫一個獨特的查詢。C#LINQ Distinct(f => f.propertyname)does not work

我不認爲Lambda表達式支持Distinct(f => f.propertyname)的管道。希望它做到了。任何人使用簡單的實現,然後使用比較器?

+0

你能發佈你的完整查詢嗎? – Dutts

+2

它被[MoreLINQ](https://www.nuget.org/packages/morelinq/1.0.16006)包含爲['DistinctBy',以下是示例源代碼](https://code.google.com/p/ morelinq/source/browse/MoreLinq/DistinctBy.cs) –

回答

5

您可以在MoreLINQ包中使用DistinctBy方法。

var result = items.DistinctBy(f => f.PropertyName); 

您可以使用DistinctBy與匿名類型以兩列獲得不同的結果。

var result = items.DistinctBy(f => new { f.Property1, f.Property2}); 
+1

'DISTINCTBY'不是標準的LINQ功能 – Amit

+1

@AmitAgrawal誰說它應該是標準功能? –

+2

@AmitAgrawal我已經說過它在MoreLINQ包中。 –

0

你不能使用這樣的獨特。編譯器無法知道要採用多個值中的哪一個。您可以使用GroupBy()來合併它們,或者根據需要使用Min(),Max(),First(),Last()或類似的方法從列表中選擇一個。

0

您有幾種選擇:

  1. 您既可以實現自定義IEqualityComparer<T>Distinct
  2. 過載或在您的類中重寫Equals + GethashCode
  3. 另一個(低效率)不需要創建新類或修改現有的方法是使用內建的GetHashCode + Equals匿名類型和Enumerable.GroupBy

    IEnumerable<Complex> distinctObjects = 
        from c in collection 
        group c by new { c.Prop1, c.Prop2 } into g 
        select g.First(); // change logic if you don't want an arbitrary object(first) 
    

這裏的第二種方法的一個例子:

public class Complex 
{ 
    public string Prop1 { get; set; } 
    public int Prop2 { get; set; } 
    public Complex Prop3 { get; set; } 

    public override bool Equals(object obj) 
    { 
     Complex c2 = obj as Complex; 
     if (obj == null) return false; 
     return Prop1 == c2.Prop1 && Prop2 == c2.Prop2; 
    } 

    public override int GetHashCode() 
    { 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = 17; 
      hash = hash * 23 + Prop1.GetHashCode(); 
      hash = hash * 23 + Prop2; 
      return hash; 
     } 
    } 
} 

EqualsIEqualityComparer -class(1 GethashCode。方法)會類似。

1

純LINQ,你可以通過你所需要的所有屬性,然後從組每組中選擇第一項:

var result = items.GroupBy(i => new { i.Prop1, i.Prop2 }) 
        .Select(g => g.First()); 

優點:

  • 你並不需要創建自定義比較,或修改你的班級,或引用第三方庫。
  • 它可以轉換爲SQL,如果你是從數據庫查詢項目

缺點在服務器端執行:

  • 使用LINQ到對象MoreLINQ的做法是更有效的(雖然你不應該這樣做過早優化)
  • MoreLINQ語法更具表現
-2

你可以用你的T動態創建一個匿名類型wo屬性,然後使用不同的。

像這樣:

[Test] 
public void Distinct_with_anonymous_type() 
{ 
    var items = new[] 
    { 
     new {p1 = 'a', p2 = 2, p3=10}, // double over p1 and p2 
     new {p1 = 'a', p2 = 3, p3=11}, 
     new {p1 = 'a', p2 = 2, p3=12}, // double over p1 and p2 
    }; 

    var expected = new[] 
    { 
     new {p1 = 'a', p2 = 2}, 
     new {p1 = 'a', p2 = 3}, 
    }; 

    var distinct = items.Select(itm => new { itm.p1, itm.p2 }).Distinct(); 

    Assert.That(distinct, Is.EquivalentTo(expected)); 
} 

希望這有助於!