2009-10-23 12 views
9

Ho un caso utilizzando TDictionary:Come creare un case in-sensitive TEqualityComparer per TDictionary?

var D: TDictionary<string, integer>; 
begin 
    D := TDictionary<string, integer>.Create(TCustomEqualityComparer.Create()); 
    try 
    D.Add('One', 1); 
    D.Add('Two', 2); 
    D.Add('Three', 3); 

    showmessage(inttostr(D.Items['One'])); 
    showmessage(inttostr(D.Items['TWO'])); 
    finally 
    D.Free; 
    end; 
end; 

Classe TCustomEqualityComparer viene copiato da Generics Defaults TEqualityComparer (Delphi) con lievi modifiche al metodo GetHashCode:

TCustomEqualityComparer = class(TEqualityComparer<string>) 
public 
    function Equals(const Left, Right: string): Boolean; override; 
    function GetHashCode(const Value: string): Integer; override; 
end; 

function TCustomEqualityComparer.Equals(const Left, Right: string): Boolean; 
begin 
    Result := SameText(Left, Right); 
end; 

function TCustomEqualityComparer.GetHashCode(const Value: string): Integer; 
begin 
    Result := BobJenkinsHash(Value[1], Length(Value) * SizeOf(Value[1]), 0); 
end; 

mi aspetto che il TCustomEqualityComparer in grado di eseguire l'abbinamento case-insensitive per la valori chiave. Ad esempio:

D.Items['TWO'] 

Tuttavia, ottengo un'eccezione "Articolo non trovato". Sto usando Delphi 2010 versione 14.0.3513.24210.

Qualcuno sa cosa c'è di sbagliato nel mio codice?

risposta

2

Grazie. Ho cambiato TCustomEqualityComparer.GetHashCode e funziona come hai detto:

function TCustomEqualityComparer.Equals(const Left, Right: string): Boolean; 
begin 
    Result := SameText(Left, Right); 
end; 

function TCustomEqualityComparer.GetHashCode(const Value: string): Integer; 
var s: string; 
begin 
    s := UpperCase(Value); 
    Result := BobJenkinsHash(s[1], Length(s) * SizeOf(s[1]), 0); 
end; 
3

HashCode deve essere lo stesso per tutti i valori che restituiscono Equals = true! Prova a fare il valore in maiuscolo nel GetHashCode prima di inviarlo alla tua HashFunction.

+0

Sei sicuro l'originale Equals è già maiuscole e minuscole? Questo è il metodo originale Equals definito nell'unità Generics.Defaults.pas: function Equals_UString (Inst: PSimpleInstance; const Left, Right: UnicodeString): Boolean; inizio Risultato: = Sinistra = Destra; fine; –

+0

Hai ragione! Ho confuso l'implementazione originale e un esempio. –

12
uses System.Generics.Collections, System.Generics.Defaults; 

var 
    D: TDictionary<string, Integer>; 
begin 
    D := TDictionary<string, Integer>.Create(TIStringComparer.Ordinal); // ‹- this is the trick 
    try 
    D.Add('One', 1); 
    . 
    . 
    finally 
    D.Free; 
    end; 
end; 
Problemi correlati