Search code examples
delphidelphi-10.2-tokyospring4d

What is the correct way to copy the dictionary?


I need to check if there has been a change in a certain part of the application and therefore I make "copies" of the data after loading them and then compare them. One part of the comparison function involves checking keys in dictionaries like lDict1.Keys.EqualsTo(lDict2.Keys).

Although the dictionaries do not rely on the order of the elements, I didn't realize that even if I fill two dictionaries with the same data, they won't be created the same and the order of elements may change, so the previous function does not work properly because it relies on the elements order that may not match when using any of the following methods. (I'm not sure why)

var
  lDict1, lDict2 : IDictionary<Integer, TObject>;
  lKey : Integer;
begin
  lDict1 := TCollections.CreateDictionary<Integer, TObject>;
  lDict1.Add(5, nil); // Keys.First = 5, Keys.Last = 5
  lDict1.Add(6, nil); // Keys.First = 5, Keys.Last = 6
  lDict2 := TCollections.CreateDictionary<Integer, TObject>;
  lDict2.AddRange(lDict1); // Keys.First = 6, Keys.Last = 5
  lDict2.Clear;
  for lKey in lDict1.Keys do // Keys.First = 6, Keys.Last = 5
    lDict2.Add(lKey, nil);
end;

Is there any way to make an exact copy of the dictionary so I can compare them? One way to work around this problem is to create my own comparison function, but I'd like to avoid that.

function ContainsSameValues<T>(AEnumerable1, AEnumerable2: IEnumerable<T>): Boolean;
var
  lValue : T;
begin
  Result := AEnumerable1.Count = AEnumerable2.Count;
  if Result then
  begin
    for lValue in AEnumerable1 do
    begin
      Result := AEnumerable2.Contains(lValue);
      if not Result then
        Exit;
    end;
  end;
end;

usage

ContainsSameValues<Integer>(lDict1.Keys, lDict2.Keys);

Solution

  • Checking for equality of a unordered dictionaries is a relatively simple algorithm. I will outline it here. Suppose we have two dictionaries, A and B.

    1. Compare the number of elements of A and B. If this differs, the dictionaries are not equal.
    2. Enumerate each key/value pair k,v in A. If k is not in B, or B[k] is not equal to v, then the dictionaries are not equal.
    3. If you reach the end of the enumeration, then you know that the dictionaries are equal.