Come si ordina un dizionario in base al valore?

Spesso devo ordinare un dizionario, composto da chiavi e valori, in base al valore. Ad esempio, ho un hash di parole e rispettive frequenze, che voglio ordinare per frequenza.

C’è una SortedList che va bene per un singolo valore (diciamo la frequenza), che voglio ricondurre alla parola.

OrdinatoDictionary ordini per chiave, non valore. Alcuni ricorrono a una lezione personalizzata , ma c’è un modo più pulito?

Uso:

 using System.Linq.Enumerable; ... List> myList = aDictionary.ToList(); myList.Sort( delegate(KeyValuePair pair1, KeyValuePair pair2) { return pair1.Value.CompareTo(pair2.Value); } ); 

Dal momento che hai scelto come target .NET 2.0 o versione successiva, puoi semplificare questo nella syntax lambda: è equivalente, ma più breve. Se stai utilizzando .NET 2.0, puoi utilizzare questa syntax solo se stai utilizzando il compilatore di Visual Studio 2008 (o successivo).

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

Usa LINQ:

 Dictionary myDict = new Dictionary(); 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; 

Ciò consentirebbe anche una grande flessibilità in quanto è ansible selezionare i primi 10, 20 10%, ecc. Oppure se si utilizza l’indice di frequenza delle parole per la type-ahead , è ansible includere anche la clausola StartsWith .

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

Guardando intorno e usando alcune funzionalità del C # 3.0 possiamo fare questo:

 foreach (KeyValuePair item in keywordCounts.OrderBy(key=> key.Value)) { // do something with item.Key and item.Value } 

Questo è il modo più pulito che ho visto ed è simile al modo in cui Ruby gestisce gli hash.

È ansible ordinare un dizionario in base al valore e salvarlo nuovamente su sé stesso (in modo tale che quando si esegue la prescansione su di esso i valori escano in ordine):

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

Certo, potrebbe non essere corretto, ma funziona.

Ad un livello elevato, non hai altra scelta che percorrere l’intero dizionario e osservare ciascun valore.

Forse questo aiuta: http://bytes.com/forum/thread563638.html Copia / Incolla da John Timney:

 Dictionary s = new Dictionary(); s.Add("1", "a Item"); s.Add("2", "c Item"); s.Add("3", "b Item"); List> myList = new List>(s); myList.Sort( delegate(KeyValuePair firstPair, KeyValuePair nextPair) { return firstPair.Value.CompareTo(nextPair.Value); } ); 

Non saresti mai in grado di ordinare un dizionario comunque. Non sono effettivamente ordinati. Le garanzie per un dizionario sono che la chiave e le collezioni di valori sono iterabili, e i valori possono essere recuperati per indice o chiave, ma qui non c’è garanzia di alcun ordine particolare. Quindi è necessario ottenere la coppia valore nome in una lista.

Non si ordinano le voci nel dizionario. La class dizionario in .NET è implementata come una tabella hash – questa struttura dati non è ordinabile per definizione.

Se è necessario essere in grado di eseguire iterazioni sulla raccolta (per chiave), è necessario utilizzare SortedDictionary, che viene implementato come albero di ricerca binario.

Nel tuo caso, tuttavia, la struttura di origine è irrilevante, perché è ordinata da un campo diverso. Dovresti comunque ordinarlo per frequenza e metterlo in una nuova raccolta ordinata per il campo pertinente (frequenza). Quindi in questa collezione le frequenze sono chiavi e le parole sono valori. Poiché molte parole possono avere la stessa frequenza (e lo si utilizzerà come chiave) non è ansible utilizzare né Dizionario né SortedDictionary (richiedono chiavi univoche). Questo ti lascia con una SortedList.

Non capisco perché insisti a mantenere un collegamento con l’articolo originale nel tuo dizionario principale / primo.

Se gli oggetti nella tua raccolta avevano una struttura più complessa (più campi) e dovevi essere in grado di accedervi / ordinarli efficientemente usando diversi campi come chiavi – Probabilmente avresti bisogno di una struttura dati personalizzata che sarebbe costituita dalla memoria principale che supporta O (1) inserimento e rimozione (LinkedList) e diverse strutture di indicizzazione – Dizionari / SortedDictionaries / SortedLists. Questi indici utilizzano uno dei campi della class complessa come chiave e un puntatore / riferimento al LinkedListNode nella LinkedList come valore.

Dovresti coordinare gli inserimenti e le rimozioni per mantenere i tuoi indici sincronizzati con la raccolta principale (LinkedList) e le rimozioni sarebbero piuttosto costose. Questo è simile a come funzionano gli indici di database: sono fantastici per le ricerche ma diventano un fardello quando è necessario eseguire molte insezioni e cancellazioni.

Tutto quanto sopra è giustificato solo se hai intenzione di eseguire alcune operazioni di ricerca pesante. Se devi solo emetterli una volta ordinati per frequenza, puoi semplicemente creare un elenco di tuple (anonime):

 var dict = new SortedDictionary(); // 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); } 
 Dictionary dic= new Dictionary(); var ordered = dic.OrderBy(x => x.Value); return ordered.ToDictionary(t => t.Key, t => t.Value); 

O per divertimento potresti usare qualche bontà di estensione LINQ:

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

Ordina valori

Mostra come ordinare i valori in un dizionario. Vediamo un programma di console che puoi compilare in Visual Studio ed eseguire. Aggiunge le chiavi a un dizionario e poi le ordina in base ai loro valori. Ricorda che le istanze del dizionario non vengono inizialmente ordinate in alcun modo. Usiamo la parola chiave orderQ LINQ in una dichiarazione di query.

OrderBy Clause Program che ordina Dictionary [C #]

 using System; using System.Collections.Generic; using System.Linq; class Program { static void Main() { // Example dictionary. var dictionary = new Dictionary(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 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; } } 

Produzione

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

Ordinamento di un elenco SortedDictionary da associare a un controllo ListView utilizzando 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:

         

Il modo più semplice per ottenere un dizionario ordinato è utilizzare la class SortedDictionary :

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

sortedSections contiene la versione ordinata delle sections

Le altre risposte sono buone, se tutto quello che vuoi è avere una lista “temporanea” ordinata per Valore. Tuttavia, se si desidera disporre di un dizionario ordinato per Key che si sincronizza automaticamente con un altro dizionario ordinato per Value , è ansible utilizzare la Bijection .

Bijection ti permette di inizializzare la raccolta con due dizionari esistenti, quindi se vuoi che uno di essi sia non ordinato, e vuoi che l’altro sia ordinato, puoi creare la tua bijection con un codice come

 var dict = new Bijection(new Dictionary(), new SortedDictionary()); 

È ansible utilizzare dict come qualsiasi dizionario normale (implementa IDictionary<> ), quindi chiamare dict.Inverse per ottenere il dizionario “inverso” ordinato per Value .

Bijection è parte di Loyc.Collections.dll , ma se vuoi, puoi semplicemente copiare il codice sorgente nel tuo progetto.

Nota : nel caso in cui vi siano più chiavi con lo stesso valore, non è ansible utilizzare Bijection , ma è ansible sincronizzare manualmente tra un Dictionary normale Dictionary e un BMultiMap .

Supponiamo di avere un dizionario come

  Dictionary dict = new Dictionary(); 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) puoi usare il temporary dictionary to store values as :

  Dictionary dctTemp = new Dictionary(); foreach (KeyValuePair pair in dict.OrderBy(key => key.Value)) { dctTemp .Add(pair.Key, pair.Value); } 

È ansible ordinare il dizionario in base al valore e ottenere il risultato nel dizionario utilizzando il seguente codice:

 Dictionary <> ShareUserNewCopy = ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key, pair => pair.Value); 

Dato che hai un dizionario puoi ordinarli direttamente sui valori usando sotto una fodera:

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