TDictionary在创建示例代码期间填充

时间:2013-01-23 22:06:27

标签: delphi

是否有人在构造函数中填充了TDictionary<TKey, TValue>的示例代码?

3 个答案:

答案 0 :(得分:4)

显然你只想要一个单行,所以我尝试了一下,实现了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可能会有问题(特别是如果你想使用两种词典),我提供了另一种语法;不幸的是,这个没有扩展,它变得非常丑陋真实:

  Dict := TDictHelper<Integer, string>.Make([1, 2], ['one', 'two']);

此替代方法为Keys和Values采用两个单独的数组,将它们组合在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.

答案 1 :(得分:3)

您需要致电dictionary constructor overload来接收类型为Collection的{​​{1}}参数。

例如,假设我们有TEnumerable<TPair<TKey, TValue>>。然后我们可以向构造函数传递TDictionary<string, Integer>的实例。这种事情的一个例子是TList<TPair<string, Integer>>

TEnumerable<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>>)

答案 2 :(得分:0)

在以下示例中,将键和值数组传递给自定义构造函数。使用以下模式将键和值放在同一个数组中: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方法的性能,但是如果你有一些项目,我认为它可以忽略不计。