A new generic type in Delphi 2009 is TDictionary. TDictionary offers a way to store values based on a key into a list. TDictionary is declared as TDictionary<TKey, TValue>.
TDictionary in fact is what a hashtable is in C#. It allows you to store/structure data based on any key type and any value type.
Suppose we want to track our persons, from the previous blogpost, on their social security number, we could put them in TDictionary like this: (using a very simple social security number....)
procedure TForm4.Button2Click(Sender: TObject);
var
Dic : TDictionary<Integer,TPerson>;
p : TPerson;
i : integer;
begin
//Create dictionary
Dic := TDictionary<Integer,TPerson>.Create;
Dic.Add(1, TPerson.Create('Delphi', 'Mr'));
Dic.Add(2, TPerson.Create('Generic', 'Bill'));
Dic.Add(3, TPerson.Create('nonymous', 'An'));
try
//Travel the strings
for p in Dic.Values do begin
ShowMessage(p.FullName);
end;
//Travel the keys
for i in Dic.Keys do begin
ShowMessage(IntToStr(i) + ': ' +
Dic.Items[i].FullName);
end;
//Find some key
if Dic.TryGetValue(3, p) then begin
ShowMessage('Found it!: ' + p.FullName);
end;
finally
for p in Dic.Values do
p.Free;
//Also free Values and KeyCollection
//other wise you have a memoryleak
//Is this a bug?
Dic.Values.Free;
Dic.Keys.Free;
//Free the dictionary
Dic.Free;
end;
I noticed that if you free the Dictionary in above scenario you must also free the Values and Keys collection to avoid a memory leak. This looks like a bug to me. (Will investigate this further)
In this sample I used an integer type as the key value, so this has not much benefit compared to an array. You can however use any type to be the key value!
Because we can store any type, we can take this a step further and put a TList<T> in our Dictionary:
Suppose we want to put our Personlist into a dictionary based on, let's say their gender. You could do that something like this:
type
PersonKind = (pkMale, pkFemale);
procedure TForm4.Button3Click(Sender: TObject);
var
Dic : TDictionary<PersonKind,TList<TPerson>>;
MPersonsList : TList<TPerson>;
FPersonsList : TList<TPerson>;
pList : TList<TPerson>;
p : TPerson;
begin
MPersonsList := TList<TPerson>.Create;
FPersonsList := TList<TPerson>.Create;
Dic := TDictionary<PersonKind,TList<TPerson>>.Create;
try
//Fill male list
MPersonsList.Add(TPerson.Create('Delphi','Mr'));
MPersonsList.Add(TPerson.Create('Generic','Bill'));
MPersonsList.Add(TPerson.Create('Nymous','Ano'));
//Fill female list
FPersonsList.Add(TPerson.Create('Delphi','Mrs'));
FPersonsList.Add(TPerson.Create('Nymous','Anna'));
//Add to dictionary
Dic.Add(pkMale, MPersonsList);
Dic.Add(pkFemale, FPersonsList);
//Travel
for p in Dic[pkMale] do begin
ShowMessage('This is a man: ' + p.FullName);
end;
for p in Dic[pkFemale] do begin
ShowMessage('This is a female: ' + p.FullName);
end;
finally
//Free Persons and Personlist
for p in MPersonsList do p.Free;
for p in FPersonsList do p.Free;
MPersonsList.Free;
FPersonsList.Free;
Dic.Free;
end;
end;
TDatadictionary is a very powerfull, yet in basic easy to use, generic type. It allows you to build simple, but also complex data structures. (What about a TDictionary with TDictionary's in it? ;-) )
Again a very nice language addition to Delphi!