¿Cuál es la forma canónica de escribir una función hasher para TEqualityComparer.Construct?

Considere el siguiente registro:

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

Deseo implementar IEqualityComparer<TMyRecord>. Para hacerlo quiero llamar TEqualityComparer<TMyRecord>.Construct. Esto debe ser suministrado con un TEqualityComparison<TMyRecord> que no presenta problemas para mí.

Sin embargo, Construct también requiere un THasher<TMyRecord> y me gustaría saber el método canónico para implementar eso. La función debe tener la siguiente forma:

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

Espero que necesito llamar BobJenkinsHash en ambos campos del valor del registro y luego combínelos de alguna manera. ¿Es este el enfoque correcto y cómo debo combinarlos?

La razón por la que no uso TEqualityComparison<TMyRecord>.Default es que usa CompareMem y por lo tanto será incorrecto debido al relleno del registro.

preguntado el 02 de julio de 12 a las 14:07

¿Se necesita realmente el valor hash en su situación? De lo contrario, supongo que el valor devuelto no se usa de todos modos, por lo que puede ser cualquier cosa, incluso un valor literal como 1. ¿O estoy equivocado aquí? -

@Rudy El valor hash no es necesario. Y podría devolver una constante que es verdadera. O levanta un EMethodNotImplemented excepción. Pero tenía curiosidad de cómo hacerlo bien. -

ah, está bien entonces. Sin embargo, la curiosidad parece hacer algo malo a los gatos. ;-)-

1 Respuestas

El Java efectivo (por Joshua Bloch) La sección sobre la anulación de hashCode podría ser útil. Muestra cómo se pueden combinar las partes individuales del objeto (o registro) para construir eficientemente un hashCode.

Una buena función hash tiende a producir códigos hash desiguales para objetos desiguales. Esto es exactamente lo que significa la tercera disposición del contrato hashCode. Idealmente, una función hash debería distribuir cualquier colección razonable de instancias desiguales de manera uniforme entre todos los valores hash posibles. Alcanzar este ideal puede ser extremadamente difícil. Afortunadamente, no es demasiado difícil lograr una aproximación justa. Aquí hay una receta simple:

  1. Almacene algún valor constante distinto de cero, digamos 17, en un int variable llamada result.
  2. Para cada campo significativo f en su objeto (es decir, cada campo tomado en cuenta por el método equals), haga lo siguiente:

    una. Calcular un int código hash c para el campo: ..... detalles omitidos ....

    B. Combine el código hash c calculado en el paso a en el resultado de la siguiente manera: result = 37*result + c;

  3. Regreso result.

  4. Cuando haya terminado de escribir el hashCode método, pregúntese si instancias iguales tienen códigos hash iguales. Si no es así, averigüe por qué y solucione el problema.

Esto se puede traducir a código Delphi de la siguiente manera:

{$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}

Esto permite entonces la implementación de MyRecordHasher:

function MyRecordHasher(const Value: TMyRecord): Integer;
begin
  Result := CombinedHash([IfThen(Value.b, 0, 1), Value.i]);
end;

Respondido 02 Jul 12, 19:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.