14

簡単に言うと、オブジェクトのコレクションが2つあります。1つには適切な値(「Good」と呼びましょう)が含まれ、もう1つにはデフォルト値(Mr.「Default」)が含まれます。グッドとデフォルト、そしてデフォルトの間の連合の交差点が欲しい。言い換えると、Intersect(Union(Good、Default)、Default)です。デフォルトとして解決されると思うかもしれませんが、ここで注意が必要です。カスタム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();
    }
}

これが私のコレクションの特徴ですGoodコレクションとDefaultコレクション:

デフォルト:これは、必要なすべての{MyString1、MyString2}ペアを含む大きなセットですが、ご想像のとおり、MyString3値はデフォルト値です。

良い:これは小さなセットで、ほとんどがデフォルトセットにあるアイテムを含みますが、いくつかの良いMyString3値が含まれています。また、必要なセットの外にある{MyString1、MyString2}もあります。

私がしたいのはこれです:デフォルトにあるGoodからのアイテムだけを取りますが、それにデフォルトにある他のアイテムを追加します。

これが、私が思うに、私の最善の試みです:

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

私はそれがうまくいくはずだと教えましたが、私が得る結果は基本的に良い{MyString1、MyString2}ペアセットだけですが、すべてデフォルトセットから来ているので、全体にデフォルト値があります。また、最後の交差のデフォルトとグッドを切り替えてみましたが、同じ結果が得られます。

4

2 に答える 2

21

まず第一に、これは間違っています:

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が提案したように(私を予想して)、コードは次のとおりです。

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 -
于 2010-12-02T21:48:53.637 に答える
10

ハッシュコードの同等性だけでなく、実際の同等性をチェックする必要があります。

GetHashCode()は衝突がないわけではありません(そしてそうすることはできません)Equals。そのため、そもそもこの方法が必要です。

また、これを書くだけでもっと簡単にできます

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

このDistinctメソッドは、重複の各ペアの最初のアイテムを返すため、目的の結果が返されます。

編集:それはする必要があります

WantedResult = Good.Intersect(Default, new MyEqualityComparer())
                   .Union(Default, new MyEqualityComparer());
于 2010-12-02T21:49:00.777 に答える