2012-05-17 10 views
18

我看了一下,找不到任何東西來幫忙。我有一個類:C#Linq相交/除了一部分對象

class ThisClass 
{ 
    private string a {get; set;} 
    private string b {get; set;} 
} 

我想用相交和除LINQ的方法,即:

private List<ThisClass> foo = new List<ThisClass>(); 
private List<ThisClass> bar = new List<ThisClass>(); 

然後我填的是兩個列表seperately。我想做的,例如(我知道這是不對的,只是僞代碼),如下:

foo[a].Intersect(bar[a]); 

我該怎麼做?

感謝所有幫助:)

+0

你想要什麼?用文字解釋你想從這行'foo [a] .Intersect(bar [a]);'。 –

回答

25

也許

// returns list of intersecting property 'a' values 
foo.Select(f => f.a).Intersect(bar.Select(b => b.a)); 

BTW財產a應該是公開的。

+0

不錯,簡單,只是我需要的。感謝你和所有答覆者。 –

2
foo.Select(x=>x.a).Intersect(bar.Select(x=>x.a)) 
16

如果你想要一個你想要交叉的屬性列表,那麼所有其他漂亮的LINQ解決方案都可以正常工作。 但是!如果你想在整個班上相交,結果有List<ThisClass>而不是List<string>,你必須編寫自己的相等比較器。

foo.Intersect(bar, new YourEqualityComparer()); 

Except相同。

public class YourEqualityComparer: IEqualityComparer<ThisClass> 
{ 

    #region IEqualityComparer<ThisClass> Members 


    public bool Equals(ThisClass x, ThisClass y) 
    { 
     //no null check here, you might want to do that, or correct that to compare just one part of your object 
     return x.a == y.a && x.b == y.b; 
    } 


    public int GetHashCode(ThisClass obj) 
    { 
     unchecked 
     { 
      var hash = 17; 
          //same here, if you only want to get a hashcode on a, remove the line with b 
      hash = hash * 23 + obj.a.GetHashCode(); 
      hash = hash * 23 + obj.b.GetHashCode(); 

      return hash;  
     } 
    } 

    #endregion 
} 
-2

您應該創建IEqualityComparer。您可以將IEqualityComparer傳遞給Intersect()方法。這將幫助您更輕鬆地獲得List(與條相交)。

var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList(); 


class ThisClassEqualityComparer : IEqualityComparer<ThisClass> 
{ 

    public bool Equals(ThisClass b1, ThisClass b2) 
    { 
     return b1.a == b2.a; 
    } 


    public int GetHashCode(Box bx) 
    { 
     // To ignore to compare hashcode, please consider this. 
     // I would like to force Equals() to be called 
     return 0; 
    } 

} 
+1

你不應該像這樣從哈希代碼返回'0'。這將徹底殺死性能。你應該使用'a'的哈希碼。 – Servy

0

究竟是期望的效果是什麼?您是否希望獲得由您的課程中的所有a組成的字符串列表或ThisClass列表,其中兩個ThisClass實例是通過唯一值a來標識的?

如果是前者,@lazyberezovksy和@Tilak的兩個答案應該可以工作。如果是後者,你就必須重寫IEqualityComparer<ThisClass>IEquatable<ThisClass>使Intersect知道是什麼使得ThisClass相當於兩個實例:

private class ThisClass : IEquatable<ThisClass> 
{ 
    private string a; 

    public bool Equals(ThisClass other) 
    { 
     return string.Equals(this.a, other.a); 
    } 
} 

那麼你可以撥打:

var intersection = foo.Intersect(bar);  
+1

實現'IEquatable'時,您總是需要重寫'GetHashCode'。既然你不這樣做,這是行不通的。 – Servy

3

不知道的速度相比,相交和比較,但如何:

//Intersect 
var inter = foo.Where(f => bar.Any(b => b.a == f.a)); 
//Except - values of foo not in bar 
var except = foo.Where(f => !bar.Any(b => b.a == f.a)); 
+3

這是一個O(n * m)算法,而'Intersect'和'Except'都是'O(n + m)'。這會讓你變得更糟。它還會多次迭代'bar',這可能是各種情況下的一個主要問題(它可能不會在每次迭代時產生相同的結果,它可能會查詢數據庫或在每次迭代中預先計算昂貴的計算,可能會產生副作用迭代時引起的等等 – Servy

0

我知道這是舊的,但你不能也只是覆蓋類本身上的等於& GetHashCode?

class ThisClass 
{ 
    public string a {get; set;} 
    private string b {get; set;} 

    public override bool Equals(object obj) 
    { 
    // If you only want to compare on a 
    ThisClass that = (ThisClass)obj; 
    return string.Equals(a, that.a/* optional: not case sensitive? */); 
    } 

    public override int GetHashCode() 
    { 
    return a.GetHashCode(); 
    } 
}