TDictionary<TKey, TValue>
コンストラクター中に入力されるコードの例はありますか?
3 に答える
どうやらあなたはワンライナーが欲しいだけなので、これを試してみTDictHelper
て、ワンライナーを使用して辞書を作成および入力できる を実装しました。
任意の形式のワンライナーを使用して Dictionary を初期化する際の問題は、値のペアが必要であり、それらのペアを渡すために必要な適切な構文がないことです。たとえばTPair<Key, Value>.Create(A, B)
、ディクショナリに追加された値のペアごとに構文を使用する必要がある場合、それは醜いワンライナーになります。
見栄えの良い代替案をいくつか見つけました。最初のものは次のように使用されます。
with TDictHelper<Integer, string> do
Dict := Make([P(1, 'one'), P(2, 'two')]);
私が実装したクラスには、パラメータとしての配列を取るルーチンがあるため、を使用するwith
必要があります。次のように書いた場合、これは使用できません。TDictHelper
Make
TPair<Key, Value>
Dict := TDictHelper<Integer, string>.Make(TPair<Integer, string>.Create(1, 'one'), TPair<Integer, string>.Create(2, 'two'));
それは機能しますが、非常に醜いでしょう!
の使用にはwith
問題が生じる可能性があるため (特に 2 種類の辞書を使用する場合)、別の構文を含めました。残念ながら、これはスケーリングされず、本当に醜いものになります。
Dict := TDictHelper<Integer, string>.Make([1, 2], ['one', 'two']);
この代替手段は、キーと値の 2 つの個別の配列を取り、それらをMake
メソッド内で結合します。要素数が 2 ~ 3 の場合は問題ないように見えますが、拡張できません。要素が 10 個あり、7 番目のペアを削除する必要がある場合はどうでしょうか。要素をカウントする必要があり、エラーが発生しやすくなります。
完全なコードは次のとおりです。
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.
type のパラメーターを受け取る辞書コンストラクター オーバーロードを呼び出す必要があります。Collection
TEnumerable<TPair<TKey, TValue>>
たとえば、 があるとしますTDictionary<string, Integer>
。次に、コンストラクターに のインスタンスを渡すことができますTEnumerable<TPair<string, Integer>>
。そのようなものの例はです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);
これは非常に扱いにくくCreate
、一連のAdd
. たまたま既製のコレクションが手元にある場合にのみ、既存のコレクションを渡すオプションを使用します。
から派生するクラスの別の例は、TEnumerable<T>
それTDictionary
自体です。
type
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
したがって、既に辞書のインスタンスが 1 つある場合は、別のインスタンスを作成して、最初の内容で初期化できます。
Dict2 := TDictionary<string, Integer>.Create(Dict1);
次の例では、キーと値の配列がカスタム コンストラクターに渡されます。キーと値は、次のパターンを使用して同じ配列に配置されます: key1、value1、key2、value2、....、keyN、valueN。配列には、偶数の項目が含まれている必要があります。
unit MainUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Generics.Collections, System.Rtti;
type
TForm3 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
TMyDictionary<TK, TV> = class(TDictionary<TK,TV>)
constructor Create(const values: array of variant);
end;
var
Form3: TForm3;
extensions: TMyDictionary<string, integer>;
implementation
constructor TMyDictionary<TK, TV>.Create(const values: array of variant);
var
I: Integer;
k, v: TValue;
kt: TK;
vt: TV;
begin
inherited Create(Length(values) div 2);
I := Low(values);
while i <= High(values) do
begin
k := TValue.FromVariant(values[i]);
v := TValue.FromVariant(values[i + 1]);
kt := k.AsType<TK>;
vt := v.AsType<TV>;
Add(kt, vt);
Inc(I, 2);
end;
end;
{$R *.dfm}
begin
extensions := TMyDictionary<string, integer>.Create(['1', 1, '3', 3]);
OutputDebugString(PChar(IntToStr(extensions['1'])));
end.
TValue メソッドのパフォーマンスについてはよくわかりませんが、アイテムがいくつかある場合は無視できると思います。