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.
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;
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;
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).