sort - foreach dictionary c#




Comment trier un dictionnaire par valeur? (12)

À un niveau élevé, vous n'avez pas d'autre choix que de parcourir tout le dictionnaire et d'examiner 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);
    }
);

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 existe une liste SortedList qui convient à une valeur unique (disons la fréquence) et que je souhaite mapper au mot.

SortedDictionary commande par clé et non par valeur. Certains ont recours à une classe personnalisée , mais existe-t-il un moyen plus propre?


Étant donné que vous avez un dictionnaire, vous pouvez les trier directement sur les valeurs en utilisant ci-dessous une ligne:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);

En fait, en C #, les dictionnaires ont des méthodes sort (), comme vous êtes plus intéressé par le tri par les valeurs, vous ne pouvez pas obtenir de valeurs tant que vous ne leur fournissez pas la clé.

var items = new Dictionary<string, int>();
items.Add("cat", 0);
items.Add("dog", 20);
items.Add("bear", 100);
items.Add("lion", 50);

// Call OrderBy method here on each item and provide them the ids.
foreach (var item in items.OrderBy(k => k.Key))
{
    Console.WriteLine(item);// items are in sorted order
}

vous pouvez faire un tour,

var sortedDictByOrder = items.OrderBy(v => v.Value);

ou

var sortedKeys = from pair in dictName
            orderby pair.Value ascending
            select pair;

cela dépend aussi du type de valeurs que vous enregistrez,
est-il simple (comme string, int) ou multiple (comme List, Array, classe définie par l'utilisateur),
Si vous êtes célibataire, vous pouvez en faire la liste, puis appliquer le tri.
si la classe définie par l'utilisateur, cette classe doit implémenter IComparable,
ClassName: IComparable<ClassName> et remplacez compareTo(ClassName c) car ils sont plus rapides que LINQ et plus orientés objet.


En regardant autour de vous 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 semblable à la méthode de gestion des hachages de Ruby.


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

Bijection<K1, K2> vous permet d’initialiser la collection avec deux dictionnaires existants. Par conséquent, si vous souhaitez que l’un d’eux soit non trié et que l’autre soit trié, vous pouvez créer votre bijection avec le code suivant:

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

Vous pouvez utiliser dict comme n'importe quel dictionnaire normal (il implémente IDictionary<K, V> ), puis appelez dict.Inverse pour obtenir le dictionnaire "inverse" trié par Value .

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 : Si plusieurs clés ont la même valeur, vous ne pouvez pas utiliser Bijection , mais vous pouvez effectuer une synchronisation manuelle entre un Dictionary<Key,Value> ordinaire Dictionary<Key,Value> et un BMultiMap<Value,Key> .


Ou pour le plaisir, vous pouvez utiliser certains avantages de l'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));

Tri d'une liste SortedDictionary à SortedDictionary à un contrôle ListView aide de 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>

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 en fonction de leurs valeurs. N'oubliez pas que les occurrences du dictionnaire ne sont initialement triées d'aucune manière. Nous utilisons le mot-clé LINQ orderby dans une instruction de requête.

Programme OrderBy Clause qui trie 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

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 souplesse dans la mesure où vous pouvez sélectionner le top 10, le 20 10%, etc. Ou si vous utilisez votre index de fréquence de mots pour la StartsWith type-ahead , vous pouvez également inclure la clause StartsWith .


Vous ne triez pas les entrées dans le dictionnaire. La classe de dictionnaire dans .NET est implémentée sous forme de 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é sous forme d'arborescence de recherche binaire.

Dans votre cas, toutefois, la structure source n'est pas pertinente, car elle est triée par un champ différent. Vous devez toujours le trier par fréquence et le placer dans une nouvelle collection triée par champ approprié (fréquence). Donc, dans cette collection, les fréquences sont des clés et les mots sont des valeurs. Étant donné que plusieurs mots peuvent avoir la même fréquence (et que vous allez l'utiliser comme clé), vous ne pouvez utiliser ni dictionnaire 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 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 les accéder / les 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. prend en charge l’insertion et la suppression de O (1) (LinkedList) et plusieurs structures d’indexation - Dictionnaires / TriésDictionnaires / TriésListes. Ces index utiliseraient l'un des champs de votre classe complexe en tant que clé et un pointeur / référence au LinkedListNode dans le LinkedList en tant que valeur.

Vous auriez besoin de coordonner les insertions et les suppressions pour que vos index restent synchronisés avec la collection principale (LinkedList). Les suppressions seraient assez coûteuses, à mon avis. 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 souhaitez effectuer un traitement lourd de la recherche. Si vous avez seulement besoin de les sortir une fois triés par fréquence, vous pouvez 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);
}

Vous pouvez trier un dictionnaire par valeur et le sauvegarder sur lui-même (pour que les valeurs soient affichées dans l'ordre):

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

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


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






dictionary