17

文字列キーとオブジェクトを含む 2 つの辞書があります。オブジェクトには 5 つのフィールドが含まれています。両方の辞書に最初に同じキーが含まれていることを確認し、これが正しい場合は、オブジェクトごとに同じ 5 つのフィールドが含まれていることを確認するエレガントな方法はありますか?

2 つの辞書には、同じ組み込みのハッシュコードか何かがありますか?

EDIT、次のコードでは機能していないようです:

Dictionary<string, MyClass> test1 = new Dictionary<string, MyClass>();
Dictionary<string, MyClass> test2 = new Dictionary<string, MyClass>();

MyClass i = new MyClass("", "", 1, 1, 1, 1);
MyClass j = new MyClass("", "", 1, 1, 1, 1);

test1.Add("1", i);
test2.Add("1", j);

bool equal = test1.OrderBy(r => r.Key).SequenceEqual(test2.OrderBy(r => r.Key));

class MyClass
{
    private string a;
    private string b;
    private long? c;
    private decimal d;
    private decimal e;
    private decimal f;

    public MyClass(string aa, string bb, long? cc, decimal dd, decimal ee, decimal ff)
    {
        a= aa;
        b= bb;
        c= cc;
        d= dd;
        e= ee;
        f= ff;
    }

これはfalseを返しますか?

4

5 に答える 5

25

使用できます

bool dictionariesEqual = 
    dic1.Keys.Count == dic2.Keys.Count &&
    dic1.Keys.All(k => dic2.ContainsKey(k) && object.Equals(dic2[k], dic1[k]));
于 2012-11-20T09:50:40.883 に答える
20

最初に、クラスでオーバーライドEqualsしてGetHashCodeメソッドを作成する必要があります。そうしないと、実際の値ではなく参照に対して比較が実行されます。(オーバーライドするコードは最後EqualsGetHashCode提供されます)、その後、次を使用できます。

var result = (dic1 == dic2) || //Reference comparison (if both points to same object)
             (dic1.Count == dic2.Count && !dic1.Except(dic2).Any());

Dictionary 内のアイテムが返される順序は undefinedであるため、 Dictionary.SequenceEqual (without OrderBy)に依存することはできません。

あなたが試すことができます:

Dictionary<string, object> dic1 = new Dictionary<string, object>();
Dictionary<string, object> dic2 = new Dictionary<string, object>();
dic1.Add("Key1", new { Name = "abc", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key2", new { Name = "DEF", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key3", new { Name = "GHI", Number = "123", Address = "def", Loc = "xyz" });
dic1.Add("Key4", new { Name = "JKL", Number = "123", Address = "def", Loc = "xyz" });

dic2.Add("Key1",new { Name = "abc",Number=  "123", Address= "def", Loc="xyz"});
dic2.Add("Key2", new { Name = "DEF", Number = "123", Address = "def", Loc = "xyz" });
dic2.Add("Key3", new { Name = "GHI", Number = "123", Address = "def", Loc = "xyz" });
dic2.Add("Key4", new { Name = "JKL", Number = "123", Address = "def", Loc = "xyz" });


bool result = dic1.SequenceEqual(dic2); //Do not use that

ほとんどの場合、上記は を返しますがtrue、 の順序付けられていない性質のために、実際にはそれに頼ることはできませんDictionary

順序も比較するので、それだけSequenceEqualに頼るのは間違っている可能性があります。両方の辞書を注文してから、次のように使用する必要があります。 SequenceEqualOrderBySequenceEqual

bool result2 = dic1.OrderBy(r=>r.Key).SequenceEqual(dic2.OrderBy(r=>r.Key));

ただし、これには複数の反復が含まれます。1 つは順序付けのため、もう 1 つは を使用して各要素を比較するためSequenceEqualです。

オーバーライドするためのコードEqualsGetHashCode

private class MyClass
{
    private string a;
    private string b;
    private long? c;
    private decimal d;
    private decimal e;
    private decimal f;

    public MyClass(string aa, string bb, long? cc, decimal dd, decimal ee, decimal ff)
    {
        a = aa;
        b = bb;
        c = cc;
        d = dd;
        e = ee;
        f = ff;
    }

    protected bool Equals(MyClass other)
    {
        return string.Equals(a, other.a) && string.Equals(b, other.b) && c == other.c && e == other.e && d == other.d && f == other.f;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((MyClass)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            var hashCode = (a != null ? a.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ (b != null ? b.GetHashCode() : 0);
            hashCode = (hashCode * 397) ^ c.GetHashCode();
            hashCode = (hashCode * 397) ^ e.GetHashCode();
            hashCode = (hashCode * 397) ^ d.GetHashCode();
            hashCode = (hashCode * 397) ^ f.GetHashCode();
            return hashCode;
        }
    }
}

Equals() と GetHashCode() をオーバーライドする正しい方法

于 2012-11-20T09:45:09.427 に答える
1

参照の等価性のみをチェックする組み込みEquals関数については、 SO に関するこの質問を参照してください。ハッシュコードは、2 つのオブジェクトが等しいかどうかを確実に伝えるものではありません。ハッシュ衝突の可能性は常にあります。等価性テストとしてハッシュコードを使用しないでください!Dictionary<T>

私は手作業でそれを行います: 両方の辞書のエントリ数を比較し、一方の辞書のキーと値のペアを反復処理し、キーがもう一方の辞書に存在するかどうかを確認し、両方の辞書の対応するオブジェクトを比較します。編集:ローリングの答えを見てください:)

于 2012-11-20T09:54:10.730 に答える
0

この場合、次のように SequenceEquals() メソッドを使用できます。

   Dictionary<string, object> d1 = new Dictionary<string, object>();
   d1.Add("first", new { Name = "TestName", Age = 12, ID = 001 }); 

   Dictionary<string, object> d2 = new Dictionary<string, object>();
   d2.Add("first", new { Name = "TestName", Age = 12, ID = 001 });

   Console.WriteLine(d1.SequenceEqual(d2)); //outputs True                

注: 簡単にするために、暗黙的なクラスを使用して辞書を埋めました。このコードは、どのオブジェクトでも同じように機能します。両方の辞書のハッシュコードは等しくありません。これは、次の手順で簡単に確認できます。

   Console.WriteLine(d1.GetHashCode() + " " + d2.GetHashCode()); //outputs different hashcodes
于 2012-11-20T09:53:29.243 に答える