16

Is there a single method or easy way how to copy one TDictionary content into another ? Let's say I have the following declarations

type
  TItemKey = record
    ItemID: Integer;
    ItemType: Integer;
  end;
  TItemData = record
    Name: string;
    Surname: string;
  end;
  TItems = TDictionary<TItemKey, TItemData>;

var
  // the Source and Target have the same types
  Source, Target: TItems;
begin
  // I can't find the way how to copy source to target
end;

and I would like to copy 1:1 the Source to Target. Is there such method for this ?

Thanks!

Martin Reiner
  • 2,167
  • 2
  • 20
  • 34

4 Answers4

29

TDictionary has a constructor that allows you to pass in another collection object, which will create the new one by copying the contents of the original. Is that what you are looking for?

constructor Create(Collection: TEnumerable<TPair<TKey,TValue>>); overload;

So you would use

Target := TItems.Create(Source);

And Target would be created as a copy of Source (or at least contain all the items in Source).

Jerry Gagnon
  • 1,131
  • 8
  • 16
2

If you want to go even further, here's another approach:

type
  TDictionaryHelpers<TKey, TValue> = class
  public
    class procedure CopyDictionary(ASource, ATarget: TDictionary<TKey,TValue>);
  end;

...implementation...

{ TDictionaryHelpers<TKey, TValue> }

class procedure TDictionaryHelpers<TKey, TValue>.CopyDictionary(ASource,
  ATarget: TDictionary<TKey, TValue>);
var
  LKey: TKey;
begin
  for LKey in ASource.Keys do
    ATarget.Add(LKey, ASource.Items[ LKey ] );
end;

usage according to your definition of Key and Value:

TDictionaryHelpers<TItemKey, TItemData>.CopyDictionary(LSource, LTarget);
  • I thinks this woud be faster: `var Item: TPair; ... for Item in ASource do ATarget.Add(Item.Key, Item.Value);` – TomCat500 Sep 04 '19 at 12:59
0

Constructing a new instance when assignment is intended can have side effects, e.g. object reference invalidation elsewhere. Generic approaches may not deep copy referenced types.

I would go with a simpler approach:

unit uExample;

interface

uses
  System.Generics.Collections;

type 
  TStringStringDictionary = class(TDictionary<string,string>)
  public
    procedure Assign(const aSSD: TStringStringDictionary);
  end;

implementation

procedure TStringStringDictionary.Assign(const aSSD: TStringStringDictionary );
var
  lKey: string;
begin
  Clear;
  for lKey in aSSD.Keys do
    Add(lKey, aSSD.Items[lKey]); // Or use copy constructors for objects to be duplicated
end;

end.
0

I think this should do the trick:

var
  LSource, LTarget: TItems;
  LKey: TItemKey;
begin
  LSource := TItems.Create;
  LTarget := TItems.Create;
  try
    for LKey in LSource.Keys do 
      LTarget.Add(LKey, LSource.Items[ LKey ]);
  finally
    LSource.Free;
    LTarget.Free;
  end; // tryf
end;
  • Can you explain why you assign LNewKey := LKey; rather than just using Lkey twice in the expression LTarget.Add(LKey, LSource.Items[ LKey ]); – RobertFrank Mar 20 '12 at 13:21
  • I thinks this woud be faster: `var Item: TPair; ... for Item in LSource do ATarget.Add(Item.Key, Item.Value);` – TomCat500 Sep 04 '19 at 13:03