Does anyone have example code of TDictionary<TKey, TValue>
being populated during its constructor?
Apparently you just want a one-liner, so I gave this a try, implemented a TDictHelper
that allows creating AND populating the dictionary using a one-liner.
The problem with initializing the Dictionary using any form of one-liner is that it needs pairs of values, and we don't have the required nice syntax to pass those pairs. For example, if one would be required to use the TPair<Key, Value>.Create(A, B)
syntax for each pair of values added to the dictionary, that would be one ugly one liner.
I did figure out a couple of good-looking alternatives; The first one is used like this:
with TDictHelper<Integer, string> do
Dict := Make([P(1, 'one'), P(2, 'two')]);
The use of the with
is required because the TDictHelper
class I implemented has a Make
routine that takes an array of TPair<Key, Value>
as parameter; This would be unusable if I wrote it as:
Dict := TDictHelper<Integer, string>.Make(TPair<Integer, string>.Create(1, 'one'), TPair<Integer, string>.Create(2, 'two'));
It would work, but it would be very, very ugly!
Since the use of the with
can be problematic (especially if you'd like to use two kinds of dictionaries), I included an alternative syntax; Unfortunately this one does not scale, it gets real ugly real fast:
Dict := TDictHelper<Integer, string>.Make([1, 2], ['one', 'two']);
This alternative takes two separate arrays for Keys and Values, combines them inside the Make
method. Looks ok for 2-3 elements, but would not scale: what if you have 10 elements and need to remove the 7th pair? You'd need to COUNT the elements and that's error-prone.
Here's the complete code, not much to it:
program Project25;
{$APPTYPE CONSOLE}
uses
SysUtils, Generics.Collections;
type
TDictHelper<Key, Value> = class
public
class function P(const K:Key; const V:Value): TPair<Key, Value>;
class function Make(init: array of TPair<Key, Value>): TDictionary<Key, Value>;overload;
class function Make(KeyArray: array of Key; ValueArray: array of Value): TDictionary<Key, Value>;overload;
end;
{ TDictHelper<Key, Value> }
class function TDictHelper<Key, Value>.Make(init: array of TPair<Key, Value>): TDictionary<Key, Value>;
var P: TPair<Key, Value>;
begin
Result := TDictionary<Key, Value>.Create;
for P in init do
Result.AddOrSetValue(P.Key, P.Value);
end;
class function TDictHelper<Key, Value>.Make(KeyArray: array of Key;
ValueArray: array of Value): TDictionary<Key, Value>;
var i:Integer;
begin
if Length(KeyArray) <> Length(ValueArray) then
raise Exception.Create('Number of keys does not match number of values.');
Result := TDictionary<Key, Value>.Create;
for i:=0 to High(KeyArray) do
Result.AddOrSetValue(KeyArray[i], ValueArray[i]);
end;
class function TDictHelper<Key, Value>.P(const K: Key;
const V: Value): TPair<Key, Value>;
begin
Result := TPair<Key, Value>.Create(K, V);
end;
// ============================== TEST CODE FOLLOWS
var Dict: TDictionary<Integer, string>;
Pair: TPair<Integer, string>;
begin
try
try
// Nice-looking but requires "with" and you can't work with two kinds of DictHelper at once
with TDictHelper<Integer, string> do
Dict := Make([P(1, 'one'), P(2, 'two')]);
// Use the array
for Pair in Dict do
WriteLn(Pair.Key, ' = ', Pair.Value);
Dict.Free;
// Passing the Keys and the Values in separate arrays; Works without "with" but it would
// be difficult to maintain for larger number of key/value pairs
Dict := TDictHelper<Integer, string>.Make([1, 2], ['one', 'two']);
// Use the array
for Pair in Dict do
WriteLn(Pair.Key, ' = ', Pair.Value);
Dict.Free;
except on E:Exception do
WriteLn(E.ClassName, #13#10, E.Message);
end;
finally ReadLn;
end;
end.
You need to call the dictionary constructor overload that receives a Collection
parameter of type TEnumerable<TPair<TKey, TValue>>
.
For example, suppose that we have TDictionary<string, Integer>
. Then we could pass to the constructor an instance of TEnumerable<TPair<string, Integer>>
. An example of such a thing is TList<TPair<string, Integer>>
.
List := TList<TPair<string, Integer>>.Create;
List.Add(TPair<string, Integer>.Create('Foo', 42));
List.Add(TPair<string, Integer>.Create('Bar', 666));
Dictionary := TDictionary<string, Integer>.Create(List);
This is very unwieldy and you would never prefer this option over a simple Create
followed by a series of calls to Add
. You would only use the option of passing in an existing collection if you happened to a ready-made one at hand.
Another example of a class that derives from TEnumerable<T>
is TDictionary
itself:
type
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
So if you already had one instance of the dictionary, you could create another one and initialise it with the contents of the first:
Dict2 := TDictionary<string, Integer>.Create(Dict1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With