如何在Delphi 2009中按字母顺序按键列出一个t字典?

如何在Delphi 2009中按字母顺序按键列出一个t字典?,delphi,generics,delphi-2009,tdictionary,Delphi,Generics,Delphi 2009,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

如何使用数字计算器按键的顺序浏览我的字典

我有这样的想法:

  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;
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;
var
Dic:t词典;
Enum:TPair;
开始
Dic:=TDictionary.create;
Dic.Add(‘累了’,‘我在这方面工作太久了’);
Dic.加上('Early','It's太早了,无法进行此项工作');
Dic.Add('HelpMe','I need some help');
Dic.Add(‘Dumb’,‘是的,我知道这个例子是Dumb’);
{我想执行以下操作,但按Enum.Key的排序顺序执行}
用于Dic do中的枚举
使用Enum.Key和Enum.Value进行一些处理;
免费;
结束;
因此,我想按照以下顺序处理我的词典:Dumb、Early、HelpMe、疲倦

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

我上面的示例代码甚至没有使用TEnumerator,所以我不知道这是如何设计的


谢谢巴里,谢谢你的回答

自从我提出这个问题以来,我对仿制药的探索很有趣。我想开始在我的代码中实现它们。“排序”问题有些令人困惑,因为泛型似乎内置了处理排序的方法,但没有关于如何进行排序的好例子或文档

最后,我按照巴里的建议做了,并在字典中建立了一个外部索引。尽管如此,这感觉还是不对

然而,接下来我有了另一个惊喜:我正试图用泛型的TDictionary替换。代码在泛型方面稍微干净了一点。但底线是TDictionary的速度比Gabr慢3倍多。1704667对TryGetValue的调用耗时0.45秒,但对Gabr例程的相同操作耗时0.12秒。我不知道为什么,但也许这就像Gabr拥有更快的散列函数和bucketing组合一样简单。或者泛型必须对每一种情况进行推广,这就必然会减慢速度


尽管如此,也许Barry或其他Delphi开发人员应该看看这一点,因为3倍的加速最终会让所有人受益。如果有选择的话,我个人宁愿使用内置在语言中的东西,也不愿使用第三方软件包(即使是和Gabr一样好的软件包)。但现在,我将继续使用GPStringHash。

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

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

  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;
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;
var
名单:TList ;;
开始
列表:=TList.Create(Dic.Keys);
尝试
列表.排序;
//现在处理已排序的项目列表
最后
列表。免费;
结束;
结束;

在我的例子中,我使用了TDictionaryTKeyCollection

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;
函数compareKey(const L,R:String):整数;
开始
结果:=SysUtils.CompareText(L,R);
结束;

函数getReverseSortedKeyArray(dictionary:TDictionary这里是一个示例代码,它通过
数组
列表
进行排序。它保留键值对关系,也可以调整为按值排序,而不是按键排序。此外,它还使用匿名方法进行排序

确保在
uses
子句中包含
Generics.Collections
Generics.Defaults
。 使用TArray进行排序的第一种方法是:

过程测试SortDictionaryViaArray;
变量
D:词典;
答:柏油;
P:TPair;
开始
D:=t字典。创建;
D.添加(“试验-6',6”);
D.添加(“测试-1',1”);
D.添加('测试-0',0);
D.添加(“测试-4',4”);
D.添加(“测试-3',3”);
D.添加('测试-5',0);
D.添加(“测试-2',2”);
A:=D.ToArray;
TArray.Sort(A,
t比较程序.构造(
函数(常数L,R:TPair):整数
开始
结果:=比较(左键,右键);
(完)
);
对于do中的P
ShowMessage(P.Key);
D.免费;
结束;
这是使用
TList

程序测试或操作列表;
变量
D:词典;
L:TList;
P:TPair;
开始
D:=t字典。创建;
D.添加(“试验-6',6”);
D.添加(“测试-1',1”);
D.添加('测试-0',0);
D.添加(“测试-4',4”);
D.添加(“测试-3',3”);
D.添加('测试-5',0);
D.添加(“测试-2',2”);
L:=TList.Create(D);
L.分类(
t比较程序.构造(
函数(常数L,R:TPair):整数
开始
结果:=比较(左键,右键);
(完)
);
对于我做的P
ShowMessage(P.Key);
D.免费;
L.免费;
结束;
其他(和不必要的)信息:
TList
方法需要释放列表,而
TArray
不需要释放。在内部,
TList
使用
TArray
(例如,
TArray
有一个
BinarySearch()
类方法,
TList
有一个BinarySearch方法)是的,很容易维护一个单独的TList作为键的排序索引。但是在泛型集合中,TEnumerator的DoMoveNext方法应该定义排序顺序,MoveNext和DoMoveNext(有什么区别?)假设允许集合枚举。这些不允许我直接枚举集合而不需要创建和维护单独的索引吗?正是这些到处都解释得很糟糕。@Barry:p.s.我在:中看到了你的答案,我很高兴你写了TEnumerable for performance first。我是其中一个m需要它所能达到的每一点速度。我现在正尝试转移到Delphi 2009的基于哈希表的泛型…随着我的进一步研究,我看到了在generics.Default中定义的所有比较器。它们看起来很有用,但如果我们只是为了维护它们,它们又有什么用呢
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;