web-dev-qa-db-ja.com

C#で配列をハッシュする

簡単な質問

GetHashCodeArrayを実装する方法。

詳細

Equalsをオーバーライドするオブジェクトがあり、次のことを確認しています。

this.array[n] == otherObject.array[n]

n内のすべてのarrayに対して。

当然、補完的なGetHashCodeを実装する必要があります。これを行うための.NETの方法があるのか​​、それとも自分で実装する必要があるのか​​、

hash = hash ^ array[n]

説明

私のオブジェクトには配列が含まれており、配列の要素のGetHashCodeに興味があります。配列の同等性に関する私のコードは、たとえば、私の質問が言うように、はっきりしていなかったかもしれませんが、GetHashCodeEqualsではありません)に興味があります。 GetHashCodeがオーバーライドされたら(Equalsなどが正しく機能するために)これを実装することは.NETの要件であるため、当然、補完的なDictionaryを実装する必要があると言います。ありがとう。

16
c z

配列の要素を使用してハッシュコードを計算するには、配列を IStructuralEquatable にキャストしてから、 GetHashCode(IEqualityComparer) メソッドを呼び出し、次のタイプの比較子を渡します。配列内の要素。

(Arrayクラスはメソッドを明示的に実装するため、キャストが必要です。)

たとえば、オブジェクトにint配列がある場合、次のようにGetHashCodeを実装できます。

public override int GetHashCode()
{
    return ((IStructuralEquatable)this.array).GetHashCode(EqualityComparer<int>.Default);
}

興味がある場合は、ArrayクラスがGetHashCodeメソッドを実装する方法を次に示します( 参照ソース から):

internal static int CombineHashCodes(int h1, int h2) {
    return (((h1 << 5) + h1) ^ h2);
}

int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
    if (comparer == null)
        throw new ArgumentNullException("comparer");
    Contract.EndContractBlock();

    int ret = 0;

    for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) {
        ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
    }

    return ret;
}

ご覧のとおり、現在の実装では配列の最後の8つの要素のみが使用されています。

10
Michael Liu

GetHashCodeを配列に自然に実装する必要があることに同意しません
変更のたびに更新する必要があります
またはその場で計算する
その場で直接比較します
SequenceEqualsはデフォルトの等式比較子を使用するため、実装する必要があります

public bool Equals

0nオブジェクトin配列

Enumerable.SequenceEqual
例があります

public static void SequenceEqualEx1()
{
    Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
    Pet pet2 = new Pet { Name = "Peanut", Age = 8 };

    // Create two lists of pets.
    List<Pet> pets1 = new List<Pet> { pet1, pet2 };
    List<Pet> pets2 = new List<Pet> { pet1, pet2 };

    bool equal = pets1.SequenceEqual(pets2);

    Console.WriteLine(
        "The lists {0} equal.",
        equal ? "are" : "are not");
}
4
paparazzo

それはあなたが望むものに依存します...

Michaelが上記で回答した1つのオプションは、配列要素に基づくハッシュコードを持つことです。これは、Equals値のセマンティクスと一致します。ただし、「ガイドラインとして、オブジェクトのハッシュはオブジェクトの存続期間全体にわたって同じである必要がある」ため、ハッシュコードを取得した後に配列が変更されないようにする必要があります。変更されないことを要求する不変のコンテナを持つことは、私にはエラーが発生しやすいように聞こえます。

もう1つ(IMOのより良いオプション)は、不変のコンテナー(つまり、ImmutableArray)に切り替えることです。そうすれば、値ベースのハッシュコードが理にかなっています。上記のようにIStructuralEquatableを使用するか、より一般的に使用できます。

    public override GetHashCode() =>
        Value.Aggregate(0, (total, next) => HashCode.Combine(total, next));

これは他の不変のコレクションでも機能します。

1
kofifus

現在のフレームワークを使用すると、使用を検討できます

int value=0;
for (var i = 0;i< this.array.Length; i++)
{
    value=HashCode.Combine(this.array[i],value);
}
0
Walter Vehoeven