Comment puis-je lister un dictionnaire Par Ordre alphabétique dans Delphi 2009?

Comment puis-je utiliser un TEnumerator pour passer en revue mon TDictionary dans l'ordre par clé?

j'ai quelque chose comme ceci:

  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;

alors je voudrais traiter mon dictionnaire dans l'ordre: muet, Early, HelpMe, Tired.

malheureusement, L'aide de Delphi est très minime dans la description comment les recenseurs en général et TEnumerator fonctionne spécifiquement et ne donne aucun exemple que je peux trouver. Il est également très peu écrit sur le web sur l'utilisation des recenseurs avec des génériques à Delphi.

et mon exemple de code ci-dessus n'utilise même pas TEnumerator, donc je suis confus quant à la façon dont tout cela est conçu pour être utilisé.


Merci Barry, pour ta réponse.

mon aventure dans les génériques depuis que j'ai posé la question était intéressante. Je voulais commencer à les implémenter dans mon code. Le problème du "tri" a été quelque peu déconcertant, car il semble que les méthodes génériques traitant du tri soient intégrées, mais il y a aucun bon exemple ou documentation sur la façon de le faire.

à la fin J'ai fait ce que Barry a suggéré et j'ai construit un index externe dans le dictionnaire. Pourtant, il ne se sent pas bien.

cependant, alors j'ai eu une autre surprise: j'ai essayé de remplacer Gabr GPStringHash avec le TDictionary du générique. Le code était un peu plus clair avec les génériques. Mais le fait est que le TDictionary était plus de 3 fois plus lent que celui de Gabr. 1 704 667 appels à TryGetValue a pris .45 secondes, mais la même opération aux routines de Gabr a pris .12 secondes. Je ne sais pas pourquoi, mais peut-être que C'est aussi simple que Gabr ayant une fonction de hachage plus rapide et une combinaison de flambage. Ou peut-être que les génériques ont dû généraliser pour chaque cas et ça le ralentit de façon inhérente.

jamais-le-moins, peut-être Barry ou les autres développeurs Delphi devraient regarder cela, parce qu'une accélération de 3 fois pourrait finalement bénéficier à tout le monde. Personnellement, je préférerais utiliser ce qui est intégré dans langue que le paquet d'une tierce partie (même aussi bon que Gabr) si on lui donne le choix. Mais pour l'instant, je m'en tiens à GPStringHash.

18
demandé sur Community 2010-03-27 08:36:06

3 réponses

dans mon cas, j'utilise le dictionnaire < String, String>.TKeyCollection classe.

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;

Exemple d'utilisation :

var
  key: String;
  keyArray : TArray<String>;
begin
    keyArray  := getSortedKeyArray (dictionary);
    for key in keyArray  do
    begin
      // ...
    end;
end;
6
répondu STB Land 2018-06-27 09:03:11

le dictionnaire est une table de hachage, donc il ne stocke pas les articles dans l'ordre trié. TEnumerator est simple - c'est juste un moyen d'itérer sur les articles.

Pour obtenir des articles dans une commande, vous devez les trier. Une façon serait de les mettre dans une liste et de trier la liste, comme ceci:

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;
21
répondu Barry Kelly 2010-03-27 06:43:18

Voici un exemple de code qui trie par Array<T> et TList<T>. Il préserve la relation de paire de valeurs clés, et il peut également être modifié pour trier par valeur au lieu de clé. Aussi, il utilise une méthode anonyme de faire le tri.

assurez-vous d'inclure Generics.Collections et Generics.Defaults dans votre uses l'article. La première méthode pour trier en utilisant 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;

et ceci utilise 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;

renseignements supplémentaires (et inutiles) : TList<T> la méthode a besoin de la liste pour être libérée, alors que le TArray<T> n'a pas besoin de libération. En interne, TList<T>TArray<T> (par exemple, TArray a un BinarySearch() méthode de classe, et TList<T> a une méthode BinarySearch).

4
répondu TByte 2013-04-18 09:42:22