2010-12-02 42 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());