Je dois souvent trier un dictionnaire, composé de clés et de valeurs, par valeur. Par exemple, j'ai un hachage de mots et de fréquences respectives, que je veux classer par fréquence.
Il y en a un SortedList
qui est bon pour une seule valeur (disons la fréquence), que je veux mettre en correspondance avec le mot.
SortedDictionary ordonne par clé, pas par valeur. Certains ont recours à une classe personnalisée , mais existe-t-il une méthode plus propre?
c#
.net
sorting
dictionary
Kalid
la source
la source
IComparer
qui fait l'affaire (c'est vrai qu'il accepte une clé à comparer, mais avec une clé, vous pouvez obtenir une valeur). ;-)Réponses:
Utilisation:
Comme vous ciblez .NET 2.0 ou supérieur, vous pouvez simplifier cela en syntaxe lambda - c'est équivalent, mais plus court. Si vous ciblez .NET 2.0, vous ne pouvez utiliser cette syntaxe que si vous utilisez le compilateur de Visual Studio 2008 (ou supérieur).
la source
myList.Sort((x,y)=>x.Value.CompareTo(y.Value));
IEnumerable
, vous pouvez donc obtenir une liste triée comme ceci:var mySortedList = myDictionary.OrderBy(d => d.Value).ToList();
Utilisez LINQ:
Cela permettrait également une grande flexibilité dans la mesure où vous pouvez sélectionner le top 10, 20 10%, etc. Ou si vous utilisez votre indice de fréquence de mot pour
type-ahead
, vous pouvez également inclure uneStartsWith
clause.la source
IEnumerable<KeyValuePair<TKey, TValue>>
ou anOrderedDictionary<TKey, TValue>
. Ou on devrait utiliser unSortedDictionary
dès le début. Pour une plaine,Dictionary
le MSDN indique clairement "L'ordre dans lequel les articles sont retournés n'est pas défini.". Il semble que le dernier montage de @ rythos42 soit à blâmer. :).ToDictionary
- les dictionnaires standard ne garantissent pas un ordre de trila source
En regardant autour de nous et en utilisant certaines fonctionnalités C # 3.0, nous pouvons le faire:
C'est la façon la plus propre que j'ai vue et elle est similaire à la manière Ruby de gérer les hachages.
la source
(for KeyValuePair<string, int> item in keywordCounts.OrderBy(key => key.Value) select item).ToDictionary(t => t.Key, t => t.Value)
- juste un petit ajout à votre réponse :) Merci, btw :)Vous pouvez trier un dictionnaire par valeur et le sauvegarder sur lui-même (de sorte que lorsque vous l'avez consulté, les valeurs sortent dans l'ordre):
Bien sûr, ce n'est peut-être pas correct, mais cela fonctionne.
la source
À un niveau élevé, vous n'avez pas d'autre choix que de parcourir l'ensemble du dictionnaire et d'examiner chaque valeur.
Peut-être que cela aide: http://bytes.com/forum/thread563638.html Copier / Coller de John Timney:
la source
De toute façon, vous ne pourrez jamais trier un dictionnaire. Ils ne sont pas réellement commandés. Les garanties pour un dictionnaire sont que les collections de clés et de valeurs sont itérables, et les valeurs peuvent être récupérées par index ou clé, mais il n'y a aucune garantie d'un ordre particulier. Par conséquent, vous auriez besoin d'obtenir la paire valeur-nom dans une liste.
la source
Vous ne triez pas les entrées du dictionnaire. La classe de dictionnaire dans .NET est implémentée comme une table de hachage - cette structure de données n'est pas triable par définition.
Si vous devez pouvoir parcourir votre collection (par clé) - vous devez utiliser SortedDictionary, qui est implémenté comme un arbre de recherche binaire.
Dans votre cas, cependant, la structure source n'est pas pertinente, car elle est triée par un champ différent. Vous auriez encore besoin de le trier par fréquence et de le mettre dans une nouvelle collection triée par le champ pertinent (fréquence). Ainsi, dans cette collection, les fréquences sont des clés et les mots sont des valeurs. Étant donné que de nombreux mots peuvent avoir la même fréquence (et que vous allez l'utiliser comme clé), vous ne pouvez pas utiliser ni Dictionary ni SortedDictionary (ils nécessitent des clés uniques). Cela vous laisse avec une SortedList.
Je ne comprends pas pourquoi vous insistez pour maintenir un lien vers l'élément d'origine dans votre dictionnaire principal / premier.
Si les objets de votre collection avaient une structure plus complexe (plus de champs) et que vous deviez pouvoir y accéder / trier efficacement en utilisant plusieurs champs différents comme clés - Vous auriez probablement besoin d'une structure de données personnalisée qui consisterait en le stockage principal qui prend en charge l'insertion et la suppression de O (1) (LinkedList) et plusieurs structures d'indexation - Dictionnaires / SortedDictionaries / SortedLists. Ces index utiliseraient l'un des champs de votre classe complexe comme clé et un pointeur / référence vers LinkedListNode dans LinkedList comme valeur.
Vous auriez besoin de coordonner les insertions et les suppressions pour garder vos index synchronisés avec la collection principale (LinkedList) et les suppressions seraient assez chères, je pense. Ceci est similaire au fonctionnement des index de base de données - ils sont fantastiques pour les recherches mais ils deviennent un fardeau lorsque vous devez effectuer de nombreuses insertions et suppressions.
Tout ce qui précède n'est justifié que si vous allez effectuer un traitement lourd de recherche. Si vous n'avez besoin de les sortir qu'une fois triés par fréquence, vous pouvez simplement produire une liste de tuples (anonymes):
la source
la source
Ou pour le plaisir, vous pouvez utiliser certains avantages de l'extension LINQ:
la source
Tri d'une
SortedDictionary
liste à lier dans unListView
contrôle à l'aide de VB.NET:XAML:
la source
La façon la plus simple d'obtenir un dictionnaire trié est d'utiliser la
SortedDictionary
classe intégrée :sortedSections
testament contient la version triée desections
la source
SortedDictionary
trie par clés. L'OP veut trier par valeur.SortedDictionary
n'aide pas dans ce cas.sorteddictionary()
toujours gagné par au moins 1 microseconde, et c'est beaucoup plus facile à gérer (car la surcharge de la reconversion en quelque chose d'interagir et de gérer facilement de la même manière qu'un dictionnaire est 0 (c'est déjà unsorteddictionary
)).Les autres réponses sont bonnes, si tout ce que vous voulez, c'est d'avoir une liste "temporaire" triée par valeur. Cependant, si vous souhaitez avoir un dictionnaire trié par
Key
qui se synchronise automatiquement avec un autre dictionnaire trié parValue
, vous pouvez utiliser laBijection<K1, K2>
classe .Bijection<K1, K2>
vous permet d'initialiser la collection avec deux dictionnaires existants, donc si vous voulez que l'un d'eux ne soit pas trié et que l'autre soit trié, vous pouvez créer votre bijection avec du code commeVous pouvez utiliser
dict
comme n'importe quel dictionnaire normal (il implémenteIDictionary<K, V>
), puis appelerdict.Inverse
pour obtenir le dictionnaire "inverse" qui est trié parValue
.Bijection<K1, K2>
fait partie de Loyc.Collections.dll , mais si vous le souhaitez, vous pouvez simplement copier le code source dans votre propre projet.Remarque : dans le cas où plusieurs clés ont la même valeur, vous ne pouvez pas les utiliser
Bijection
, mais vous pouvez synchroniser manuellement entre un ordinaireDictionary<Key,Value>
et unBMultiMap<Value,Key>
.la source
Supposons que nous ayons un dictionnaire comme
1) vous pouvez utiliser
temporary dictionary to store values as
:la source
En fait, en C #, les dictionnaires ont des méthodes sort (), car vous êtes plus intéressé par le tri par valeurs, vous ne pouvez pas obtenir de valeurs jusqu'à ce que vous leur fournissiez la clé, bref, vous devez les parcourir, en utilisant Order By de LINQ,
vous pouvez faire un tour,
ou
Cela dépend également du type de valeurs que vous stockez, est-il unique (comme chaîne, entier) ou multiple (comme Liste, Tableau, classe définie par l'utilisateur),
si unique, vous pouvez en faire une liste puis appliquer le tri.
si la classe est définie par l'utilisateur, cette classe doit implémenter IComparable
ClassName: IComparable<ClassName>
et remplacercompareTo(ClassName c)
car elles sont plus rapides que LINQ et plus orientées objet.la source
Espace de noms requis:
using System.Linq;
Trier par desc:
Ordre par Asc:
la source
Vous pouvez trier le dictionnaire par valeur et obtenir le résultat dans le dictionnaire en utilisant le code ci-dessous:
la source
Étant donné que vous avez un dictionnaire, vous pouvez les trier directement sur les valeurs en utilisant ci-dessous une ligne:
la source