Question Comment trier un dictionnaire par valeur?


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 commander par fréquence.

Il y a un SortedList ce qui est bon pour une seule valeur (disons la fréquence), que je veux mapper au mot.

SortedDictionary commandes par clé, pas de valeur. Certains ont recours à classe personnalisée, mais y a-t-il un moyen plus propre?


685
2017-08-02 00:40


origine


Réponses:


Utilisation:

using System.Linq.Enumerable;
...
List<KeyValuePair<string, string>> myList = aDictionary.ToList();

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

Puisque vous ciblez .NET 2.0 ou supérieur, vous pouvez le simplifier 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).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));

466
2017-08-02 01:15



Utilisez 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 le fait que vous pouvez sélectionner le top 10, 20 10%, etc. Ou si vous utilisez votre index de fréquence de mots pour type-ahead, vous pouvez également inclure StartsWith clause aussi bien.


479
2017-08-04 15:22



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

185
2017-11-11 17:16



En regardant autour, et en utilisant certaines fonctionnalités 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 manière la plus propre que j'ai vue et elle est similaire à la façon Ruby de manipuler les hachages.


149
2017-08-02 00:43



Vous pouvez trier un dictionnaire par valeur et le sauvegarder sur lui-même (de sorte que lorsque vous le recouvrez, les valeurs apparaissent dans l'ordre):

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

Bien sûr, ce n'est peut-être pas correct, mais ça fonctionne.


142
2018-06-22 10:26



À un niveau élevé, vous n'avez pas d'autre choix que de parcourir le Dictionnaire entier et de regarder chaque valeur.

Peut-être que cela aide: http://bytes.com/forum/thread563638.html Copier / Coller de John Timney:

Dictionary<string, string> s = new Dictionary<string, string>();
s.Add("1", "a Item");
s.Add("2", "c Item");
s.Add("3", "b Item");

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

57
2017-08-02 00:47



Vous ne seriez jamais capable de trier un dictionnaire de toute façon. 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 que les valeurs peuvent être récupérées par index ou par clé, mais il n'y a aucune garantie d'ordre particulier. Par conséquent, vous auriez besoin d'obtenir la paire de valeur de nom dans une liste.


22
2017-12-19 22:47



Vous ne triez pas les entrées dans le dictionnaire. La classe de dictionnaire dans .NET est implémentée sous forme de hashtable - 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é en tant qu'arborescence 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 devrez toujours trier par fréquence et le mettre dans une nouvelle collection triée par le champ pertinent (fréquence). Donc, dans cette collection, les fréquences sont des clés et les mots sont des valeurs. Comme de nombreux mots peuvent avoir la même fréquence (et que vous allez l'utiliser comme une clé), vous ne pouvez pas utiliser ni Dictionary ni SortedDictionary (ils nécessitent des clés uniques). Cela vous laisse avec une liste triée.

Je ne comprends pas pourquoi vous insistez pour maintenir un lien vers l'élément original dans votre dictionnaire principal / premier.

Si les objets de votre collection avaient une structure plus complexe (plus de champs) et que vous deviez être capable de les accéder / trier efficacement en utilisant plusieurs champs différents en tant que clés - Vous auriez probablement besoin d'une structure de données personnalisée constituée du stockage principal supporte O (1) insertion et suppression (LinkedList) et plusieurs structures d'indexation - Dictionnaires / SortedDictionaries / SortedLists. Ces index utiliseraient l'un des champs de votre classe complexe comme une clé et un pointeur / référence au LinkedListNode dans LinkedList comme une valeur.

Vous devez coordonner les insertions et les suppressions pour que vos index restent synchronisés avec la collection principale (LinkedList) et les suppressions seraient très coûteuses 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 effectuez un traitement lourd de recherche. Si vous avez seulement besoin de les sortir une fois triés par fréquence alors vous pourriez simplement produire une liste de tuples (anonymes):

var dict = new SortedDictionary<string, int>();
// ToDo: populate dict

var output = dict.OrderBy(e => e.Value).Select(e => new {frequency = e.Value, word = e.Key}).ToList();

foreach (var entry in output)
{
    Console.WriteLine("frequency:{0}, word: {1}",entry.frequency,entry.word);
}

16
2017-12-13 06:19



Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);

12
2017-07-20 11:01



Ou pour le plaisir, vous pouvez utiliser un peu d'extension LINQ:

var dictionary = new Dictionary<string, int> { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
  .ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));

10
2018-06-30 11:12



Trier les valeurs

Cela montre comment trier les valeurs dans un dictionnaire. Nous voyons un programme de console que vous pouvez compiler dans Visual Studio et exécuter. Il ajoute des clés à un dictionnaire, puis les trie selon leurs valeurs. Rappelez-vous que les instances de dictionnaire ne sont pas triées d'une manière ou d'une autre. Nous utilisons le mot-clé LINK orderby dans une requête.

Clause OrderBy Programme qui trie le dictionnaire [C #]

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // Example dictionary.
        var dictionary = new Dictionary<string, int>(5);
        dictionary.Add("cat", 1);
        dictionary.Add("dog", 0);
        dictionary.Add("mouse", 5);
        dictionary.Add("eel", 3);
        dictionary.Add("programmer", 2);

        // Order by values.
        // ... Use LINQ to specify sorting by value.
        var items = from pair in dictionary
                orderby pair.Value ascending
                select pair;

        // Display results.
        foreach (KeyValuePair<string, int> pair in items)
        {
            Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
        }

        // Reverse sort.
        // ... Can be looped over in the same way as above.
        items = from pair in dictionary
        orderby pair.Value descending
        select pair;
    }
}

Sortie

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5

10
2017-07-20 09:49