Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can I List a TDictionary in Alphabetical Order by Key in Delphi 2009?

How can I use a TEnumerator to go through my TDictionary in sorted order by key?

I've got something like this:

  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;

So I would like to process my dictionary in the order: Dumb, Early, HelpMe, Tired.

Unfortunately the Delphi help is very minimal in describing how enumerators in general and TEnumerator specifically works and gives no examples that I can find. There is also very little written on the web about using Enumerators with Generics in Delphi.

And my sample code above doesn't even use TEnumerator, so I'm confused as to how this is all designed to be used.


Thanks Barry, for your answer.

My venture into Generics since I asked the question was interesting. I wanted to start implementing them in my code. The "sorting" problem was somewhat perplexing, since it appears that Generics seem to have methods dealing with sorting built in, but there's no good examples or documentation on how to do it.

In the end I did what Barry suggested and built an external index into Dictionary. Still, it doesn't feel right.

However, then I had another surprise: I was attempting to replace Gabr's GPStringHash with the Generic's TDictionary. The code was a little cleaner with the generics. But the bottom line was that TDictionary was over 3 times slower than Gabr's. 1,704,667 calls to TryGetValue took .45 seconds, but the same operation to Gabr's routines took .12 seconds. I'm not sure why, but maybe its as simple as Gabr having a faster Hash function and bucketing combination. Or maybe the generics had to generalize for every case and that inherently slows it down.

Never-the-less, maybe Barry or the other Delphi developers should look at this, because a 3 times speedup could ultimately benefit everyone. I would personally sooner use what's built into the language than a 3rd party package (even one as good as Gabr's) if given the choice. But for now, I'll stick to GPStringHash.

like image 911
lkessler Avatar asked Mar 27 '10 05:03

lkessler


1 Answers

The dictionary is a hash table, so it doesn't store items in sorted order. TEnumerator is simple - it just a means of iterating over items.

To get items in an order, you need to sort them. One way would be to put them into a list and sort the list, like this:

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;
like image 91
Barry Kelly Avatar answered Oct 08 '22 08:10

Barry Kelly