886 votes

Comment trier un dictionnaire par valeur ?

J'ai souvent un dictionnaire de clés et de valeurs et j'ai besoin de le trier par valeur. Par exemple, j'ai un hachage de mots et de leurs fréquences, et je veux les ordonner par fréquence.

Il y a SortedList ce qui est bon pour une valeur unique (fréquence), mais je veux le faire correspondre au mot.

SortedDictionary commande par clé, et non par valeur. Certains ont recours à un classe personnalisée mais quel est le moyen le plus propre ?

1 votes

Outre le simple fait de trier le dictionnaire (comme dans la réponse acceptée), vous pouvez aussi simplement créer un fichier IComparer qui fait l'affaire (il est vrai qu'il accepte une clé pour comparer, mais avec une clé, on peut obtenir une valeur) ;-)

1 votes

@BrainSlugs83 - "créer un IComparer" n'est pas une solution complète. Veuillez préciser comment cet IComparer serait utilisé pour produire un résultat ordonné.

0 votes

Un dictionnaire trié n'a pas de sens car on accède à un dictionnaire par clé. Si vous voulez une liste triée de toutes les clés et valeurs, convertissez-la en liste, puis triez-la.

559voto

caryden Points 4195

Pourquoi ne pas utiliser LINQ :

Dictionary<string, int> myDict = new Dictionary<string, int>();
myDict.Add("one", 1);
myDict.Add("four", 4);
myDict.Add("two", 2);
myDict.Add("three", 3);

var sortedDict = from entry in myDict orderby entry.Value ascending select entry;

Cela permettrait également une grande flexibilité dans la mesure où vous pouvez sélectionner les 10, 20 ou 10% les plus importants, etc. Ou si vous utilisez votre indice de fréquence des mots pour type-ahead vous pouvez également inclure StartsWith également.

16 votes

Comment puis-je retransformer sortedDict en Dictionary<string, int> ? J'ai posté une nouvelle question sur le SO ici : stackoverflow.com/questions/3066182/

1 votes

Malheureusement, cela ne fonctionne pas sur VS2005 en raison du cadre .net 2.0 (pas de LINQ). Il est bon d'avoir également la réponse de Bambrick.

0 votes

Excellente réponse. Et, comme mentionné dans d'autres commentaires sur d'autres réponses, assurez-vous d'inclure "using System.Linq ;" en haut du fichier. Sinon, vous obtenez des messages d'erreur quelque peu déroutants et IntelliSense ne vous aide pas.

548voto

Leon Bambrick Points 10886
List<KeyValuePair<string, string>> myList = aDictionary.ToList();

myList.Sort(
    delegate(KeyValuePair<string, string> firstPair,
    KeyValuePair<string, string> nextPair)
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);

Si votre cible est .net 2.0 ou plus, vous pouvez simplifier cela en utilisant la syntaxe lambda - c'est équivalent mais plus court. Si vous visez .net 2.0, vous ne pouvez utiliser cette syntaxe que si vous utilisez le compilateur de vs2008 (ou supérieur).

List<KeyValuePair<string, string>> myList = aDictionary.ToList();

myList.Sort((firstPair,nextPair) =>
    {
        return firstPair.Value.CompareTo(nextPair.Value);
    }
);

27 votes

J'ai utilisé cette solution (Merci !) mais j'ai été confus pendant une minute jusqu'à ce que je lise le post de Michael Stum (et son extrait de code de John Timney) et que je réalise que myList est un objet secondaire, une liste de KeyValuePairs, qui est créée à partir du dictionnaire, puis triée.

3 votes

Je suis désolé mais cette réponse était difficile à comprendre car je ne suis pas familier avec le mot-clé delegate (peut-être différent en vb), et il n'est pas clair où le tri se produit car il faudrait soit faire des comparaisons entre le nombre d'éléments multiplié par le nombre d'éléments (nombre d'éléments au carré) en cherchant/comparant chaque élément au dictionnaire entier pour chaque élément, ou si vous faites juste une comparaison entre le courant et le dernier alors vous devriez le faire dans plus d'une boucle sur la collection, c'est pourquoi je ne l'ai pas 'compris' tel quel. peut-être que plus d'informations sur l'endroit où le tri et le réordonnancement se produisent aurait été utile !

116 votes

C'est une ligne unique - Vous n'avez pas besoin d'accolades. il peut être réécrit comme suit myList.Sort((x,y)=>x.Value.CompareTo(y.Value));

317voto

seanlinmt Points 3032

Vous pourriez utiliser :

var ordered = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);

40 votes

C'est une bonne solution, mais il faudrait ajouter ceci juste avant le point-virgule final : .ToDictionary(paire => paire.Key, paire => paire.Value) ;

0 votes

Je préfère celui-ci, propre et simple. @Gravitas : Je suis d'accord, et la version framework n'était pas mentionnée dans l'OP.

0 votes

Parce que cela nécessite un retour au dictionnaire, ce qui n'est pas toujours évident...

173voto

Kalid Points 6290

En regardant autour de nous, et en utilisant certaines fonctionnalités de C# 3.0, nous pouvons le faire :

foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value))
{ 
    // do something with item.Key and item.Value
}

C'est la méthode la plus propre que j'ai vue et elle est similaire à la façon dont Ruby gère les hachages.

7 votes

N'oubliez pas d'ajouter l'espace de nom System.Linq lorsque vous utilisez cette syntaxe.

4 votes

(for KeyValuePair<string, int> item in keywordCounts.OrderBy(key => key.Value) select item).ToDictionary(t => t.Key, t => t.Value) - juste un petit complément à votre réponse :) Merci, au fait :)

9 votes

@AndriusNaruševicius : Si vous rajoutez les éléments résultants dans un dictionnaire, vous détruirez l'ordre, comme les dictionnaires ne sont pas garantis d'être ordonnés d'une manière particulière .

168voto

Matt Frear Points 6287

Pour trier un dictionnaire par valeur et le sauvegarder sur lui-même (de sorte que lorsque vous effectuez un foreach sur celui-ci, les valeurs sortent dans l'ordre) :

dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);

11 votes

Vous pouvez également utiliser OrderByDescending si vous souhaitez trier dans une liste décroissante.

0 votes

Ça a marché pour moi, bien que j'aie dû le modifier légèrement pour.. : Dictionary<key, value> dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value) ;

20 votes

Ce "travail" n'est pas garanti. C'est un détail de mise en œuvre. Il n'est pas nécessaire que cela fonctionne à d'autres moments. Mauvaise réponse, downvoted.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X