c# - Comment triez-vous un dictionnaire par valeur?

Translate

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

Il y a unSortedListce qui est bon pour une valeur unique (disons fréquence), que je veux mapper sur le mot.

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

This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

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 simplifier cela dans la 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));
La source
Translate

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 la mesure où vous pouvez sélectionner les 10 premiers, 20 à 10%, etc. Ou si vous utilisez votre index de fréquence de mot pourtype-ahead, vous pouvez également inclureStartsWithclause aussi.

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

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 manière la plus propre que j'ai vue et est similaire à la manière Ruby de gérer les hachages.

La source
Translate

Vous pouvez trier un dictionnaire par valeur et le sauvegarder sur lui-même (de sorte que lorsque vous le parcourez, 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 cela fonctionne.

La source
Translate

À 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.htmlCopier / 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);
    }
);
La source
Translate

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 que les valeurs peuvent être récupérées par index ou par clé, mais il n'y a aucune garantie d'un ordre particulier. Par conséquent, vous devez obtenir la paire de valeur de nom dans une liste.

La source
Translate

Vous ne triez pas les entrées du dictionnaire. La classe Dictionary dans .NET est implémentée sous forme de table de hachage - cette structure de données ne peut pas être triée par définition.

Si vous avez besoin de pouvoir parcourir votre collection (par clé), vous devez utiliser SortedDictionary, qui est implémenté en tant qu'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 devrez toujours le 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. É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 comprendrait le stockage principal qui prend en charge l'insertion et la suppression d'O (1) (LinkedList) et plusieurs structures d'indexation - Dictionaries / SortedDictionaries / SortedLists. Ces index utiliseraient l'un des champs de votre classe complexe comme clé et un pointeur / référence vers le 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 intensif de recherche. Si vous n'avez besoin de les afficher qu'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);
}
La source
Translate
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
La source
Translate

Ou pour le plaisir, vous pouvez utiliser les 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));
La source
Translate

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 instances de dictionnaire ne sont en aucun cas triées initialement. Nous utilisons le mot clé LINQ orderby dans une instruction de requête.

OrderBy Clause 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;
    }
}

Production

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
La source
Translate

Trier unSortedDictionaryliste à lier dans unListViewcontrôle à l'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>
La source
Translate

Le moyen le plus simple d'obtenir un dictionnaire trié est d'utiliser la fonction intégréeSortedDictionaryclasse:

//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);
}

sortedSectionswill contient la version triée desections

La source
Translate

Les autres réponses sont bonnes, si tout ce que vous voulez est d'avoir une liste "temporaire" triée par Valeur. Cependant, si vous souhaitez avoir un dictionnaire trié parKeycettesynchronise automatiquementavec un autre dictionnaire trié parValue, vous pouvez utiliser leBijection<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 vous voulez que l'autre soit trié, vous pouvez créer votre bijection avec du code comme

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

Vous pouvez utiliserdictcomme n'importe quel dictionnaire normal (il implémenteIDictionary<K, V>), puis appelezdict.Inversepour obtenir le dictionnaire "inverse" qui est trié parValue.

Bijection<K1, K2>fait partie deLoyc.Collections.dll, mais si vous le souhaitez, vous pouvez simplement copier lecode sourcedans votre propre projet.

Remarque: Si plusieurs clés ont la même valeur, vous ne pouvez pas utiliserBijection, mais vous pouvez synchroniser manuellement entre unDictionary<Key,Value>et unBMultiMap<Value,Key>.

La source
Translate

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 utilisertemporary 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);
        }
La source
Translate

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

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
}

tu peux faire un tour,

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

or

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

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

La source
Translate

Vous pouvez trier le dictionnaire par 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);                                          
La source
Translate

É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);
La source