7

文字列プロパティを持つクラスがあり、GetHashCode() メソッドをオーバーライドする必要があります。

class A
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

最初のアイデアは、次のようにすることです。

public override int GetHashCode()
{
    return Prop1.GetHashCode() ^ Prop2.GetHashCode() ^ Prop3.GetHashCode();
}

2番目のアイデアは次のとおりです。

public override int GetHashCode()
{
    return String.Join(";", new[] {Prop1, Prop2, Prop3}).GetHashCode();
}

最善の方法は何ですか?

4

2 に答える 2

4

これは順序付けを考慮していないため、それらを単に XOR するべきではありません。2 つのオブジェクトがあるとします。

"foo", "bar", "baz"

"bar", "foo", "baz"

単純な XOR を使用すると、これらは両方とも同じハッシュになります。幸いなことに、回避するのはかなり簡単です。これは、ハッシュを結合するために使用するコードです。

static int MultiHash(IEnumerable<object> items)
{
    Contract.Requires(items != null);

    int h = 0;

    foreach (object item in items)
    {
         h = Combine(h, item != null ? item.GetHashCode() : 0);
    }

    return h;
}

static int Combine(int x, int y)
{
    unchecked
    {
         // This isn't a particularly strong way to combine hashes, but it's
         // cheap, respects ordering, and should work for the majority of cases.
         return (x << 5) + 3 + x ^ y;
    }
}

ハッシュを組み合わせる方法はたくさんありますが、通常はこのような非常に単純なもので十分です。何らかの理由でそれがうまくいかない場合、MurmurHashには非常に堅牢なハッシュ結合があり、プルすることができます。

于 2012-12-10T16:54:31.523 に答える
3

各文字列のハッシュを XOR するだけです。これは、文字列の連結よりも (パフォーマンス面で) 安価であり、私が見る限り、衝突が発生しにくいというわけではありません。各文字列の長さは 5 文字で、各文字が 1 バイトを占めると仮定しましょう。最初のものでは、15 バイトを 4 バイト (int) にハッシュしています。2 番目の例では、3 つの文字列すべてを連結して (コストのかかる操作)、最終的に 15 バイトの文字列を 1 つにし、それを 4 バイトにハッシュしています。どちらも 15 バイトを 4 に変換するため、理論的には衝突に関してはどちらも非常に似ています。

実際に、衝突の確率には多少の違いがありますが、実際には常に問題になるとは限りません。文字列が持つデータによって異なります。3 つの文字列がすべて等しく、それぞれがハッシュされている場合0001(例のために単純な数値を使用しています)。3つすべてが等しい場合、最初の2つをxorすると取得さ0000れ、3番目のものをxorすると に戻ります0001。文字列を連結することで、ある程度のパフォーマンスを犠牲にしてこれを回避できます (パフォーマンスが重要なプログラムを作成している場合は、内側のループで文字列を連結しません)。

結局のところ、私は実際には答えを出していません。単純な理由は、実際には答えがないからです。それはすべて、どこでどのように使用されるかによって異なります。

于 2012-12-10T15:48:14.973 に答える