Comment trier vous un dictionnaire en valeur?

voix
671

Je dois souvent trier un dictionnaire, composé de clés et de valeurs, en termes de valeur. Par exemple, j'ai un hachage des mots et des fréquences respectives, que je veux commander par fréquence.

Il y a un SortedListqui est bon pour une seule valeur (disons fréquence), que je veux revenir à la carte du mot.

SortedDictionary commandes de valeur clé, non. Certains recourent à une classe personnalisée , mais est - il un moyen plus propre?

Créé 02/08/2008 à 01:40
source utilisateur
Dans d'autres langues...                            


17 réponses

voix
473

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 ce que 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 la StartsWithclause aussi.

Créé 04/08/2008 à 16:22
source utilisateur

voix
459

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 plus, vous pouvez simplifier la syntaxe dans lambda - il est équivalent, mais plus court. Si vous ciblez .NET 2.0 vous ne pouvez utiliser cette syntaxe si vous utilisez le compilateur à partir de Visual Studio 2008 (ou plus).

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
Créé 02/08/2008 à 02:15
source utilisateur

voix
179
var ordered = dict.OrderBy(x => x.Value);
Créé 11/11/2010 à 18:16
source utilisateur

voix
148

En regardant autour, et en utilisant des C # 3.0 fonctionnalités que 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 façon la plus propre que je l'ai vu et est similaire à la façon dont Ruby de manutention hash.

Créé 02/08/2008 à 01:43
source utilisateur

voix
140

Vous pouvez trier un dictionnaire en valeur et enregistrez-le à lui-même (de sorte que lorsque vous foreach dessus les valeurs sont dans l'ordre):

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

Bien sûr, il ne peut pas être correct, mais il fonctionne.

Créé 22/06/2011 à 11:26
source utilisateur

voix
56

Sur un niveau élevé, vous avez pas d'autre choix que de marcher à travers tout le dictionnaire et regarder chaque valeur.

Peut-être 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);
    }
);
Créé 02/08/2008 à 01:47
source utilisateur

voix
22

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 principales collections et la valeur sont itératives, et les valeurs peuvent être récupérées par index ou une clé, mais est ici aucune garantie d'un ordre particulier. Par conséquent, vous devrez obtenir la paire de valeurs de nom dans une liste.

Créé 19/12/2008 à 23:47
source utilisateur

voix
16

Vous n'êtes pas trier les entrées dans le dictionnaire. classe Dictionary dans .NET est mis en œuvre en tant que Hashtable - cette structure de données ne sont pas sortable par définition.

Si vous devez être en mesure de parcourir votre collection (par clé) - vous devez utiliser SortedDictionary, qui est implémenté comme un arbre de recherche binaire.

Dans votre cas, mais la structure de source est hors de propos, car il est trié par un autre champ. Vous auriez encore besoin de faire le tri par la fréquence et le mettre dans une nouvelle collection triée par le domaine concerné (fréquence). Donc, dans cette collection les fréquences sont les clés et les mots sont des valeurs. Étant donné que beaucoup de mots peuvent avoir la même fréquence (et vous allez l'utiliser comme une clé) vous ne pouvez pas utiliser ni dictionnaire, ni SortedDictionary (ils nécessitent des clés uniques). Cela vous laisse avec un SortedList.

Je ne comprends pas pourquoi vous insistez sur le maintien d'un lien vers l'élément d'origine dans votre principale / premier dictionnaire.

Si les objets de votre collection ont une structure plus complexe (plus de champs) et vous avez besoin pour pouvoir efficacement l'accès / les trier en utilisant plusieurs champs différents comme clés - Vous auriez probablement besoin d'une structure de données personnalisée qui comprend le stockage principal qui soutient O (1) insertion et de retrait (LinkedList) et plusieurs structures d'indexation - dictionnaires / SortedDictionaries / SortedLists. Ces indices utiliseraient un des champs de votre classe complexe comme une clé et un pointeur / référence à la LinkedListNode dans LinkedList en tant que valeur.

Vous auriez besoin de coordonner les insertions et les suppressions pour garder vos index en phase avec la collection principale (LinkedList) et le transfert serait assez cher je pense. Ceci est similaire à la façon dont les index de base de données fonctionnent - ils sont fantastiques pour, mais ils deviennent lookups un fardeau lorsque vous devez effectuer de nombreuses insetions et suppressions.

Tous ce qui précède ne se justifie que si vous allez faire un peu de consultation traitement lourd. Si vous avez seulement besoin de les sortir une fois trié par fréquence alors vous pouvez produire une liste de (anonyme) tuples:

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);
}
Créé 13/12/2012 à 07:19
source utilisateur

voix
12
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Créé 20/07/2015 à 11:01
source utilisateur

voix
10

Les valeurs de tri

Cette montre comment trier les valeurs dans un dictionnaire. Nous voyons un programme de console, vous pouvez compiler dans Visual Studio et exécuter. Il ajoute des clés à un dictionnaire et les trie ensuite par leurs valeurs. Rappelez-vous que les instances Dictionnaire ne sont pas initialement classés en aucune façon. Nous utilisons le mot-clé orderby LINQ dans une instruction de requête.

OrderBy Programme de l'article triant 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
Créé 20/07/2012 à 10:49
source utilisateur

voix
10

Ou pour le plaisir, vous pouvez utiliser une bonté 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));
Créé 30/06/2010 à 12:12
source utilisateur

voix
9

Trier une SortedDictionaryliste de se lier à un ListViewcontrôle en utilisant VB.NET:

Dim MyDictionary As SortedDictionary(Of String, MyDictionaryEntry)

MyDictionaryListView.ItemsSource = MyDictionary.Values.OrderByDescending(Function(entry) entry.MyValue)

Public Class MyDictionaryEntry ' Need Property for GridViewColumn DisplayMemberBinding
    Public Property MyString As String
    Public Property MyValue As Integer
End Class

XAML:

<ListView Name="MyDictionaryListView">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyString}" Header="MyStringColumnName"></GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Path=MyValue}" Header="MyValueColumnName"></GridViewColumn>
         </GridView>
    </ListView.View>
</ListView>
Créé 23/04/2010 à 10:36
source utilisateur

voix
5

Les autres réponses sont bonnes, si vous tout ce que vous voulez est d'avoir une liste « temporaire » trié par valeur. Toutefois, si vous voulez avoir un dictionnaire trié par Keyqui synchronise automatiquement avec un autre dictionnaire qui est triée par Value, vous pouvez utiliser la Bijection<K1, K2>classe .

Bijection<K1, K2> vous permet d'initialiser la collection avec deux dictionnaires existants, donc si vous voulez un d'entre eux d'être non triés, et que vous voulez l'autre à trier, vous pouvez créer votre bijection avec le code comme

var dict = new Bijection<Key, Value>(new Dictionary<Key,Value>(), 
                               new SortedDictionary<Value,Key>());

Vous pouvez utiliser dictcomme tout le dictionnaire normal (il met en œuvre IDictionary<>), puis appeler dict.Inversepour obtenir le dictionnaire « inverse » qui est triée par Value.

Bijection<K1, K2>fait partie de Loyc.Collections.dll , mais si vous voulez, vous pouvez simplement copier le code source dans votre propre projet.

Remarque : Dans le cas où il y a plusieurs touches avec la même valeur, vous ne pouvez pas utiliser Bijection, mais vous pouvez synchroniser manuellement entre un ordinaire Dictionary<Key,Value>et un BMultiMap<Value,Key>.

Créé 26/02/2016 à 07:15
source utilisateur

voix
5

La meilleure façon d'obtenir un dictionnaire trié est d'utiliser le construit en SortedDictionaryclasse:

//Sorts sections according to the key value stored on "sections" unsorted dictionary, which is passed as a constructor argument
System.Collections.Generic.SortedDictionary<int, string> sortedSections = null;
if (sections != null)
{
    sortedSections = new SortedDictionary<int, string>(sections);
}

sortedSections volonté contient la version triée de sections

Créé 02/04/2010 à 23:36
source utilisateur

voix
4

Supposons que nous ayons un dictionnaire comme

   Dictionary<int, int> dict = new Dictionary<int, int>();
   dict.Add(21,1041);
   dict.Add(213, 1021);
   dict.Add(45, 1081);
   dict.Add(54, 1091);
   dict.Add(3425, 1061);
   sict.Add(768, 1011);

1) vous pouvez utiliser temporary dictionary to store values as:

        Dictionary<int, int> dctTemp = new Dictionary<int, int>();

        foreach (KeyValuePair<int, int> pair in dict.OrderBy(key => key.Value))
        {
            dctTemp .Add(pair.Key, pair.Value);
        }
Créé 02/02/2015 à 10:46
source utilisateur

voix
-2

Étant donné que vous avez un dictionnaire, vous pouvez les trier directement sur les valeurs en utilisant en dessous d'un revêtement:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Créé 31/05/2014 à 23:30
source utilisateur

voix
-2

Vous pouvez trier le dictionnaire en valeur et obtenir le résultat dans le dictionnaire en utilisant le code ci-dessous:

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Créé 24/07/2012 à 13:24
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more