代码之家  ›  专栏  ›  技术社区  ›  lkessler

在Delphi2009中,如何按键按字母顺序列出TDictionary?

  •  18
  • lkessler  · 技术社区  · 15 年前

    如何使用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;
    

    所以我想按顺序处理我的字典:哑,早,帮我,累。

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

    我上面的示例代码甚至都不使用tenumerator,所以我很困惑这一切是如何设计来使用的。


    谢谢巴里的回答。

    自从我问起这个问题以来,我对泛型的研究很有意思。我想开始在代码中实现它们。“排序”问题有些令人困惑,因为泛型似乎内置了处理排序的方法,但是没有很好的示例或文档说明如何进行排序。

    最后,我按照巴里的建议,在字典中建立了一个外部索引。不过,感觉还是不对。

    然而,后来我又有了一个惊喜:我正试图取代 Gabr GPStringHash 使用泛型的tdictionary。使用泛型的代码稍微干净一点。但归根结底,tdictionary的速度比gabr的慢3倍多。调用trygetvalue需要0.45秒,但对gabr例程的相同操作需要0.12秒。我不知道为什么,但也许它和gabr一样简单,它有一个更快的散列函数和bucketing组合。或者泛型必须对每一种情况进行泛化,这就降低了泛型的速度。

    永远不要少,也许巴里或其他德尔福开发人员应该看看这一点,因为3倍的加速最终会使每个人受益。如果可以选择的话,我个人更愿意使用语言内置的东西,而不是第三方软件包(甚至是像gabr那样好的软件包)。但现在,我还是坚持使用gpstringhash。

    3 回复  |  直到 7 年前
        1
  •  6
  •   Stéphane B. Ronan Quillevere    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;
    
        2
  •  21
  •   Barry Kelly    15 年前

    字典是一个哈希表,因此它不按排序顺序存储项。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;
    
        3
  •  4
  •   TByte    12 年前

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

    一定要包括 Generics.Collections Generics.Defaults 在你 uses 条款。 第一种排序方法 TArray<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;
    

    这是在用 列表<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;
    

    附加(和不必要)信息: 这个 列表<t> 方法需要释放列表,而 tarray<t> 不需要释放。内部, 列表<t> 使用 tarray<t> (例如, TArray 有一个 BinarySearch() 类方法,以及 列表<t> 具有BinarySearch方法)。