【问题标题】:What is the canonical way to write a hasher function for TEqualityComparer.Construct?为 IEqualityComparer.Construct 编写散列函数的规范方法是什么?
【发布时间】:2012-07-02 13:27:28
【问题描述】:

考虑以下记录:

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

我希望实现IEqualityComparer<TMyRecord>。为此,我想致电TEqualityComparer<TMyRecord>.Construct。这需要提供TEqualityComparison<TMyRecord>,这对我没有任何问题。

但是,Construct 也需要THasher<TMyRecord>,我想知道实现它的规范方法。该函数需要具有以下形式:

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

我希望我需要在记录值的两个字段上调用BobJenkinsHash,然后以某种方式将它们组合起来。这是正确的方法吗?我应该如何将它们结合起来?

我不使用TEqualityComparison<TMyRecord>.Default 的原因是它使用了CompareMem,因此由于记录的填充而将不正确。

【问题讨论】:

  • 在您的情况下,是否真的需要哈希值?否则,我假设返回的值无论如何都不会被使用,所以它可以是任何东西,甚至是像 1 这样的文字值。还是我错了?
  • @Rudy 不需要哈希值。我可以返回一个真实的常量。或者引发EMethodNotImplemented 异常。但我很好奇如何正确地做到这一点。
  • 啊,那好吧。不过,好奇心似乎对猫不利。 ;-)

标签: delphi hash delphi-xe2


【解决方案1】:

关于覆盖 hashCode 的 Effective Java (by Joshua Bloch) 部分可能很有用。它展示了如何组合对象(或记录)的各个部分以有效地构造 hashCode。

一个好的散列函数往往会为不等生成不等的散列码 对象。这正是第三条规定的意思 哈希码合约。理想情况下,散列函数应该分发任何 合理地收集所有不相等的实例 可能的哈希值。实现这一理想可能非常困难。 幸运的是,实现一个公平的近似并不难。这里 是一个简单的食谱:

  1. 在名为resultint 变量中存储一些恒定的非零值,例如17。
  2. 对于对象中的每个重要字段f(即equals方法考虑的每个字段),请执行以下操作:

    一个。计算字段的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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-21
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多