什么是正确的字典复制方式?

3

我需要检查应用程序的某个部分是否发生了变化,因此在加载数据后制作"副本",然后进行比较。比较函数的一部分涉及检查像lDict1.Keys.EqualsTo(lDict2.Keys)这样的字典键。

虽然字典不依赖于元素的顺序,但我没有意识到即使用相同的数据填充两个字典,它们也不会被创建为相同的,并且元素的顺序可能会改变,因此之前的函数无法正常工作,因为它依赖于元素的顺序,而这些顺序可能在使用以下方法之一时不匹配。(我不确定为什么)

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;

有没有办法制作一个完全相同的字典副本以进行比较?解决这个问题的一种方法是创建自己的比较函数,但我想避免这样做。

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;

使用方法

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

2
没有一种保证可以制作出“精确副本”的方式(即保留键的顺序)。 - Olivier
2
最新的Spring版本中的字典实现是有序的。我在新的字典实现上做了原始工作,这是基于Python有序字典进行建模的。话虽如此,我不确定使用有序字典是否足以解决你的问题。毕竟,你真的想知道项目是否按相同顺序添加,还是实际上想知道字典是否包含相同的键值对呢? - David Heffernan
4
对于我来说,如果你想检查两个字典是否相等,只需要枚举其中一个字典的键值对,并检查它们是否在另一个字典中也存在。如果这两个字典具有相同数量的项,并且其中一个字典的所有键值对都可以在另一个字典中找到,则它们是相同的。 - David Heffernan
@LURD 嗯,我认为排序是你最不想做的事情。 - David Heffernan
@DavidHeffernan,排序和排序是相关的,我认为。无论如何,正如您建议的那样,匹配对将是最终解决方案。为什么不把它作为答案呢? - LU RD
显示剩余3条评论
1个回答

4

检查无序字典的相等性是一个相对简单的算法,我将在此概述它。假设我们有两个字典A和B。

  1. 比较A和B的元素数量。如果不同,则字典不相等。
  2. 枚举A中的每个键/值对k,v。如果k不在B中,或者B[k]不等于v,则字典不相等。
  3. 如果你到达了枚举的末尾,则知道这两个字典是相等的。

这不够。即使B包含比A更多的键,该算法仍确定A等于B。您还必须检查B的所有键是否以相同的值存在于A中。 - Heinz Z.
2
@Heinz 请再次阅读第一项。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接