5

次のレコードを検討してください。

TMyRecord = record
  b: Boolean;
  // 3 bytes of padding in here with default record alignment settings
  i: Integer;
end;

実装したいIEqualityComparer<TMyRecord>。そうするために、私は電話したいと思いますTEqualityComparer<TMyRecord>.ConstructTEqualityComparison<TMyRecord>これは私に問題を提示しないで供給される必要があります。

ただし、Constructaも必要であり、THasher<TMyRecord>それを実装するための標準的な方法を知りたいと思います。関数は次の形式である必要があります。

function MyRecordHasher(const Value: TMyRecord): Integer;
begin
  Result := ???
end;

BobJenkinsHashレコード値の両方のフィールドを呼び出して、それらを何らかの方法で組み合わせる必要があると思います。これは正しいアプローチですか、そしてそれらをどのように組み合わせる必要がありますか?

私が使用しない理由は、レコードのパディングのためTEqualityComparison<TMyRecord>.Defaultに使用するCompareMemため、正しくないためです。

4

1 に答える 1

6

hashCodeのオーバーライドに関するEffectiveJava(Joshua Blochによる)セクションが役立つ可能性があります。これは、オブジェクト(またはレコード)の個々の部分を組み合わせて、hashCodeを効率的に構築する方法を示しています。

優れたハッシュ関数は、等しくないオブジェクトに対して等しくないハッシュコードを生成する傾向があります。これはまさに、hashCodeコントラクトの3番目のプロビジョニングが意味するものです。理想的には、ハッシュ関数は、等しくないインスタンスの合理的なコレクションをすべての可能なハッシュ値に均一に分散する必要があります。この理想を達成することは非常に難しい場合があります。幸いなことに、公正な近似を達成することはそれほど難しくありません。簡単なレシピは次のとおりです。

  1. 定数の非ゼロ値、たとえば17を。というint変数に格納しますresult
  2. オブジェクトの重要なフィールドごとにf(つまり、equalsメソッドによって考慮される各フィールド)、次のようにします。

    a。intフィールドのハッシュコードを計算しcます:.....詳細は省略されています...。

    b。ステップaで計算されたハッシュコードcを次のように結果に結合します。result = 37*result + c;

  3. 戻りresultます。

  4. メソッドの記述が完了したらhashCode、等しいインスタンスに等しいハッシュコードがあるかどうかを自問してください。そうでない場合は、理由を理解して問題を修正してください。

これは、次のようにDelphiコードに変換できます。

{$IFOPT Q+}
  {$DEFINE OverflowChecksEnabled}
  {$Q-}
{$ENDIF}
function CombinedHash(const Values: array of Integer): Integer;
var
  Value: Integer;
begin
  Result := 17;
  for Value in Values do begin
    Result := Result*37 + Value;
  end;
end;
{$IFDEF OverflowChecksEnabled}
  {$Q+}
{$ENDIF}

これにより、次の実装が可能になりますMyRecordHasher

function MyRecordHasher(const Value: TMyRecord): Integer;
begin
  Result := CombinedHash([IfThen(Value.b, 0, 1), Value.i]);
end;
于 2012-07-02T13:58:46.963 に答える