Mi piacerebbe avere un dizionario che restituisce un valore predefinito quando la chiave di ricerca non viene trovata. Leggendo dalla documentazione:Delphi Generics> Dizionario con valore predefinito
Generics.Collections.Tdictionary [...] Questa classe fornisce una mappatura [...] e il contenuto iniziale.
1 - Come? C'è un modo per farlo in Python: {1: 'one'; 2: "due"}?
Generics.Collections.TDictionary.TryGetValue [...] TryGetValue restituisce true se la chiave specificata è nel dizionario e fornisce il valore in Valore. In caso contrario, restituisce false e Valore viene impostato sul tipo di valore predefinito di Tvalue.
2 - Come posso impostare questo valore predefinito? Non riesco a trovare un costruttore (potrebbe essere che ho appena cercato nel posto sbagliato. Mi aspetto qualcosa del tipo "costruttore Create (DefaultValue: TValue);)
Quindi sto cercando di implementare il mio (può essere non è necessario Vedi sopra.): (! recensioni e suggerimenti sono ben accetti)
Il codice è:
unit Util;
interface
uses
Generics.collections;
type
//
// Dictionary with default response
//
TDefaultDictonary<K, V> = class(TObjectDictionary<K, V>)
private
M_DefaultValue : V;
public
constructor Create(Defaultvalue : V);
destructor Destroy; reintroduce;
function GetDefaultValue : V;
function TryGetValue(const Key: K; out Value: V): Boolean;
function GetValueOf(const Key: K) : V;
end;
implementation
//
// Contructor and destructor
//
constructor TDefaultDictonary<K, V>.Create(Defaultvalue : V);
begin
inherited Create;
M_DefaultValue := Defaultvalue;
end;
destructor TDefaultDictonary<K, V>.Destroy;
begin
inherited Destroy;
end;
//
// Get the default Value
//
function TDefaultDictonary<K, V>.GetDefaultValue : V;
begin
Result := M_DefaultValue;
end;
//
// Try to get a value from the dictionary for the given key.
//
// If the value is found then "Value" holds it and the function returns true.
// If the value is not found then "Value" holds the default value and the
// function returns false.
//
function TDefaultDictonary<K, V>.TryGetValue(const Key: K; out Value: V): Boolean;
var
IsKeyFound : boolean;
DictVal : V;
begin
IsKeyFound := inherited TryGetValue(Key, DictVal);
if not IsKeyFound then begin
DictVal := M_DefaultValue;
end;
// Outputs:
Value := DictVal;
Result := IsKeyFound;
end;
//
// Get a value from the dictionary for the given key.
//
// If the value is found then the function returns it.
// If the value is not found the function returns the default value.
//
function TDefaultDictonary<K, V>.GetValueOf(const Key: K) : V;
var
DictVal : V;
begin
TryGetValue(Key, DictVal);
Result := DictVal;
end;
e le prove sono:
unit Test_Utils;
{
Test the TDefaultDictionary functionality
}
interface
uses
Sysutils, Math, TestFramework, Util;
type
TestUtil = class(TTestCase)
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestDefaultDictionaryGetDefaultResponse;
procedure TestDefaultDictionaryExistingKey;
procedure TestDefaultDictionaryNotExistingKey;
end;
implementation
procedure TestUtil.SetUp;
begin
end;
procedure TestUtil.TearDown;
begin
end;
procedure TestUtil.TestDefaultDictionaryGetDefaultResponse;
var
dd : TDefaultDictonary<integer, string>;
begin
dd := TDefaultDictonary<integer, string>.Create('Default response');
checkEquals('Default response', dd.GetDefaultValue);
dd.Free;
end;
procedure TestUtil.TestDefaultDictionaryExistingKey;
var
dd : TDefaultDictonary<integer, string>;
outVal : string;
isKeyFound : boolean;
begin
dd := TDefaultDictonary<integer, string>.Create('Default response');
dd.Add(1, 'My one');
checkEquals(1, dd.Count,
'One element as count');
isKeyFound := dd.TryGetValue(1, outVal);
check(isKeyFound,
'Key not found by TryGetValue');
checkEquals('My one', outVal,
'Value given by TryGetValue');
checkEquals('My one', dd[1],
'Value given by indexing as array');
dd.Free;
end;
procedure TestUtil.TestDefaultDictionaryNotExistingKey;
var
dd : TDefaultDictonary<integer, string>;
outVal : string;
isKeyFound : boolean;
begin
dd := TDefaultDictonary<integer, string>.Create('Default response');
dd.Add(1, 'one');
isKeyFound := dd.TryGetValue(2, outVal);
check(not isKeyFound,
'Key should not be found by TryGetValue');
checkEquals('Default response', outVal,
'Default Value given by TryGetValue');
checkEquals('Default response', dd.GetValueOf(2),
'Default Value given by indexing as array');
//
// It is possible to oveload the indexer operator?
// Please review or delete me !
//
//checkEquals('Default response', dd[2],
// 'Value given by indexing as array');
//
dd.Free;
end;
initialization
RegisterTest(TestUtil.Suite);
end.
Questo è lontano da essere completo. Mi piacerebbe che anche l'operatore indicizzatore funzioni (vedi l'ultimo test). È possibile? Cosa dovrebbe essere anche implementato?
Fa questa implementazione perde M_DefaultValue (Sono nuovo a Delphi). Non posso fare qualcosa M_DefaultValue.Free nel distruttore (non è così flessibile a causa del vincolo del costruttore) Cosa si può fare qui?
Grazie in anticipo,
Francesco
Hai sollevato una domanda molto buona, poiché attualmente, in Delphi, dobbiamo fare due ricerche nel dizionario. Lo stesso vale per PHP. –