2010-12-02 79 views
13

長話短說:我有2個對象集合。一個包含很好的值(我們稱之爲「良好」),其他的默認值(先生「默認」)。我想要在「良好」和「默認」之間的聯盟交叉點,以及「默認」。換句話說:相交(聯盟(好,默認),默認)。有人可能會認爲它解決爲默認,但這裏是棘手的地方:我使用自定義的IEqualityComparer。使用Linq與自定義IEqualityComparer相交

我得到了以下類別:

class MyClass 
{ 
    public string MyString1; 
    public string MyString2; 
    public string MyString3; 
} 

class MyEqualityComparer : IEqualityComparer<MyClass> 
{ 
    public bool Equals(MyClass item1, MyClass item2) 
    { 
     if(item1 == null && item2 == null) 
      return true; 
     else if((item1 != null && item2 == null) || 
       (item1 == null && item2 != null)) 
      return false; 

     return item1.MyString1.Equals(item2.MyString1) && 
       item1.MyString2.Equals(item2.MyString2); 
    } 

    public int GetHashCode(MyClass item) 
    { 
     return new { item.MyString1, item.MyString2 }.GetHashCode(); 
    } 
} 

這是我收藏好,並默認集合的特點:

默認:這是一個大組,包含了所有的希望{MyString1,MyString2}對,但你可以猜到MyString3的值是默認值。

好:它是一個較小的集合,主要包含默認集合中的項目,但具有一些好的MyString3值。它也有一些{MyString1,MyString2}在想要的集合之外。

我想要做的是:只從Good中的項目處於默認狀態,但將Default中的其他項目添加到該項目中。

這裏,我的想法是,我最好的嘗試:

HalfWantedResult = Good.Union(Default, new MyEqualityComparer()); 
WantedResult= HalfWantedResult.Intersect(Good, new MyEqualityComparer()); 

我教它應該有工作,但結果我得到的是基本上只有良好{MyString1,MyString2}對置,但是所有來自默認設置,所以我有所有的默認值。我也嘗試切換最後一個Intersect的Default和Good,但是我得到了相同的結果。

+3

你的Equals實現是非常糟糕的。會有散列衝突,不應該在那裏。爲什麼不使用相同的投影(`new {item.MyString1,item.MyString2}`)但調用Equals? – 2010-12-02 21:48:11

+0

我應該看看這個,它可能是問題的一部分。 Union使用GetHashCode,Intersects使用Equals。我沒有真正把任何教育納入這一部分。 *慚愧* – Tipx 2010-12-02 21:51:20

回答

18

這一切首先是錯誤的:

public bool Equals(MyClass item1, MyClass item2) 
{ 
    return GetHashCode(item1) == GetHashCode(item2); 
} 

如果哈希碼的是肯定的相應的2項是不同的不同的,但如果他們是平等的,不能保證相應的2項是相等的。

因此,這是正確的Equals實現:

public bool Equals(MyClass item1, MyClass item2) 
{ 
    if(object.ReferenceEquals(item1, item2)) 
     return true; 
    if(item1 == null || item2 == null) 
     return false; 
    return item1.MyString1.Equals(item2.MyString1) && 
      item1.MyString2.Equals(item2.MyString2); 
} 

由於Slacks suggested(期待我)的代碼如下:

var Default = new List<MyClass> 
{ 
    new MyClass{MyString1="A",MyString2="A",MyString3="-"}, 
    new MyClass{MyString1="B",MyString2="B",MyString3="-"}, 
    new MyClass{MyString1="X",MyString2="X",MyString3="-"}, 
    new MyClass{MyString1="Y",MyString2="Y",MyString3="-"}, 
    new MyClass{MyString1="Z",MyString2="Z",MyString3="-"}, 

}; 
var Good = new List<MyClass> 
{ 
    new MyClass{MyString1="A",MyString2="A",MyString3="+"}, 
    new MyClass{MyString1="B",MyString2="B",MyString3="+"}, 
    new MyClass{MyString1="C",MyString2="C",MyString3="+"}, 
    new MyClass{MyString1="D",MyString2="D",MyString3="+"}, 
    new MyClass{MyString1="E",MyString2="E",MyString3="+"}, 
}; 
var wantedResult = Good.Intersect(Default, new MyEqualityComparer()) 
         .Union(Default, new MyEqualityComparer()); 

// wantedResult: 
// A A + 
// B B + 
// X X - 
// Y Y - 
// Z Z - 
+0

+1幫助我很多與我的Equals,但沒有被接受,因爲它不能解決問題。 (我希望我能+2!:-P) – Tipx 2010-12-02 22:01:48

10

您需要檢查的實際平等,不只是哈希碼平等。

GetHashCode()不是(也不能)無碰撞,這就是爲什麼首先需要Equals方法。

此外,你可以做到這一點更簡單地寫

WantedResult = Good.Concat(Default).Distinct(); 

Distinct方法將返回每一對重複的第一個項目,所以這將返回所需的結果。

編輯:這應該是

WantedResult = Good.Intersect(Default, new MyEqualityComparer()) 
        .Union(Default, new MyEqualityComparer()); 
相關問題