19

如何使用 TEnumerator 按键按排序顺序浏览我的 TDictionary?

我有这样的事情:

  var
    Dic: TDictionary<string, string>;
    Enum: TPair<string, string>;

  begin
    Dic := TDictionary<string, string>.create;
    Dic.Add('Tired', 'I have been working on this too long');
    Dic.Add('Early', 'It is too early in the morning to be working on this');
    Dic.Add('HelpMe', 'I need some help'); 
    Dic.Add('Dumb', 'Yes I know this example is dumb');

   { I want to do the following but do it in sorted order by Enum.Key }
    for Enum in Dic do
      some processing with Enum.Key and Enum.Value;

    Dic.Free;
  end;

所以我想按顺序处理我的字典:Dumb、Early、HelpMe、Tired。

不幸的是,Delphi 的帮助在描述一般的枚举器和 TEnumerator 的具体工作方式方面非常少,并且没有给出我能找到的示例。网上也很少有关于在 Delphi 中使用枚举器和泛型的文章。

而且我上面的示例代码甚至没有使用 TEnumerator,所以我对这一切是如何设计使用的感到困惑。


谢谢巴里,你的回答。

自从我问这个问题以来,我对泛型的冒险很有趣。我想开始在我的代码中实现它们。“排序”问题有点令人困惑,因为泛型似乎内置了处理排序的方法,但没有很好的示例或文档说明如何做到这一点。

最后,我按照 Barry 的建议做了,并在 Dictionary 中建立了一个外部索引。不过,感觉还是不太对。

然而,我有另一个惊喜:我试图用通用的 TDictionary 替换GabrGPStringHash。使用泛型的代码更简洁一些。但底线是 TDictionary 比 Gabr 慢 3 倍多。对 TryGetValue 的 1,704,667 次调用耗时 0.45 秒,但对 Gabr 例程的相同操作耗时 0.12 秒。我不知道为什么,但也许它就像 Gabr 一样简单,具有更快的哈希函数和分桶组合。或者,也许泛型必须针对每种情况进行泛化,这本质上会减慢速度。

尽管如此,也许 Barry 或其他 Delphi 开发人员应该看看这一点,因为 3 倍的加速最终可以使每个人受益。如果可以选择,我个人会更早地使用语言中内置的内容,而不是第三方包(甚至与 Gabr 的包一样好)。但现在,我会坚持使用 GPStringHash。

4

3 回答 3

21

字典是一个哈希表,因此它不会按排序顺序存储项目。TEnumerator 很简单——它只是一种迭代项目的方法。

要按顺序获取项目,您需要对它们进行排序。一种方法是将它们放入列表中并对列表进行排序,如下所示:

var
  list: TList<string>;
begin
  list := TList<string>.Create(Dic.Keys);
  try
    list.Sort;
    // process sorted list of items now
  finally
    list.Free;
  end;
end;
于 2010-03-27T06:43:18.397 回答
7

就我而言,我使用 TDictionary < String, String >。TKeyCollection类。

function compareKey(const L, R: String): Integer;
begin
  Result := SysUtils.CompareText(L, R);
end;

function getReverseSortedKeyArray(dictionary: TDictionary<String, String): TArray<String>;
var
  keyArray: TArray<String>;
  keyCollection: TDictionary<String, String>.TKeyCollection;
begin
  keyCollection:= TDictionary<String, String>.TKeyCollection.Create(dictionary);
  try
    keyArray:= keyCollection.ToArray;
    TArray.Sort<String>(keyArray, TComparer<String>.Construct(compareKey));
  finally
    keyCollection.Free;
  end;

  Result := keyArray;
end;

使用示例:

var
  key: String;
  keyArray : TArray<String>;
begin
    keyArray  := getSortedKeyArray (dictionary);
    for key in keyArray  do
    begin
      // ...
    end;
end;
于 2013-04-11T07:23:46.423 回答
5

这是一个通过Array<T>或排序的示例代码TList<T>。它保留了键值对关系,也可以调整为按值而不是键排序。此外,它使用匿名方法进行排序。

请务必在您的条款中包含Generics.Collections和。使用排序的第一种方法:Generics.DefaultsusesTArray<T>

procedure TestSortDictionaryViaArray;
var
  D: TDictionary<string, Integer>;
  A: TArray<TPair<string, Integer>>;
  P: TPair<string, Integer>;
begin
  D := TDictionary<string, Integer>.Create;

  D.Add('Test - 6', 6);
  D.Add('Test - 1', 1);
  D.Add('Test - 0', 0);
  D.Add('Test - 4', 4);
  D.Add('Test - 3', 3);
  D.Add('Test - 5', 0);
  D.Add('Test - 2', 2);

  A := D.ToArray;

  TArray.Sort<TPair<string, Integer>>(A,
    TComparer<TPair<string, Integer>>.Construct(
      function (const L, R: TPair<string, Integer>): Integer
      begin
        Result := CompareStr(L.Key, R.Key);
      end)
  );

  for P in A do
    ShowMessage(P.Key);
  D.Free;
end;

这是使用TList<T>

procedure TestSortDictionaryViaList;
var
  D: TDictionary<string, Integer>;
  L: TList<TPair<string, Integer>>;
  P: TPair<string, Integer>;
begin
  D := TDictionary<string, Integer>.Create;

  D.Add('Test - 6', 6);
  D.Add('Test - 1', 1);
  D.Add('Test - 0', 0);
  D.Add('Test - 4', 4);
  D.Add('Test - 3', 3);
  D.Add('Test - 5', 0);
  D.Add('Test - 2', 2);

  L := TList<TPair<string, Integer>>.Create(D);

  L.Sort(
    TComparer<TPair<string, Integer>>.Construct(
      function (const L, R: TPair<string, Integer>): Integer
      begin
        Result := CompareStr(L.Key, R.Key);
      end)
  );

  for P in L do
    ShowMessage(P.Key);

  D.Free;
  L.Free;
end;

附加(和不必要的)信息:该TList<T>方法需要释放列表,TArray<T>而不需要释放。在内部,TList<T>使用TArray<T>(例如,TArray有一个BinarySearch()类方法,并且TList<T>有一个 BinarySearch 方法)。

于 2013-04-18T09:42:22.053 回答