Domanda

Mi capita spesso di dover ordinare un dizionario, che consiste di chiavi e valori, in base al valore.Per esempio, ho un hash di parole e le rispettive frequenze, che voglio ordinare in base alla frequenza.

C'è un SortedList che è buono per un singolo valore (diciamo frequenza), che voglio mappa di nuovo la parola.

Insieme sorteddictionary ordini chiave, non il valore.Alcuni resort per un classe personalizzata, ma c'è un modo più pulito?

È stato utile?

Soluzione

Uso:

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

Dal momento che stai targeting .NET 2.0 o superiore, si può semplificare in questo lambda sintassi -- è equivalente, ma più breve.Se stai targeting .NET 2.0 non è possibile utilizzare questa sintassi, se si utilizza il compilatore di Visual Studio 2008 (o sopra).

var myList = aDictionary.ToList();

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

Altri suggerimenti

Utilizzare 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;

Questo permetterebbe anche di grande flessibilità in quanto è possibile selezionare la top 10, 20 del 10%, etc.O se si utilizza la parola indice di frequenza per type-ahead, si potrebbe anche includere StartsWith clausola così.

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

Si guarda intorno, e l'utilizzo di C# 3.0 caratteristiche che possiamo fare questo:

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

Questo è il modo più pulito ho visto ed è simile al Rubino il modo di gestire gli hash.

È possibile ordinare un Dizionario di valore e salvarlo di nuovo a se stesso (in modo che quando si foreach su di esso i valori vengono fuori, nell'ordine:

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

Certo, potrebbe non essere corretto, ma funziona.

Su un livello elevato, non hai altra scelta quindi di camminare attraverso l'intero Dizionario e guardare ogni valore.

Forse questo aiuta:http://bytes.com/forum/thread563638.html Copia/Incolla da Giovanni 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);
    }
);

Non ti saresti mai essere in grado di ordinare un dizionario in ogni caso.Essi non sono in realtà ordinato.Le garanzie per un dizionario che la chiave e il valore collezioni sono iterable, e i valori possono essere recuperati da un indice o la chiave, ma non vi è alcuna garanzia di alcun ordine particolare.Quindi, si avrebbe bisogno di avere la coppia nome / valore in un elenco.

Non ordinare le voci del Dizionario.Dizionario di classe .NET è implementato come una hashtable - questa struttura di dati non è ordinabile per definizione.

Se avete bisogno di essere in grado di scorrere la vostra collezione (con chiave) - è necessario utilizzare insieme sorteddictionary, che è implementato come un Albero di Ricerca Binaria.

Nel tuo caso, tuttavia, la struttura di origine è irrilevante, perché è ordinato da un campo diverso.Si sarebbe ancora bisogno di ordinamento dalla frequenza e metterlo in una nuova collezione ordinati per il campo relativo (frequenza).Così, in questa collezione, le frequenze, le chiavi e le parole sono i valori.Dal momento che molte parole possono avere la stessa frequenza (e avete intenzione di usarlo come una chiave) non è possibile utilizzare né Dizionario né insieme sorteddictionary (che non richiedono chiavi univoche).Questo ti lascia con una SortedList.

Non capisco perché ti ostini a mantenere un link per l'articolo originale in/primo dizionario.

Se gli oggetti nella vostra collezione ha una struttura più complessa (più campi) e avete bisogno di essere in grado di accedere in modo efficiente e ordinamento di loro utilizzando diversi campi, come chiavi - Si sarebbe probabilmente bisogno di un personalizzato della struttura di dati che sarebbero la principale di archiviazione che supporta O(1) l'inserimento e la rimozione (LinkedList) e diverse strutture di indicizzazione - Dizionari/SortedDictionaries/SortedLists.Questi indici potrebbero utilizzare uno dei campi della classe complessa come una chiave e di un puntatore/riferimento all'LinkedListNode in LinkedList come un valore.

Si avrebbe bisogno di coordinare gli inserimenti e rimozioni per mantenere il vostro indici in sincronia con collezione principale (LinkedList) e l'assorbimento sarebbe abbastanza costoso, credo.Questo è simile a come indici del database di lavoro sono fantastici per le ricerche, ma diventano un peso, quando è necessario eseguire molti insetions e delezioni.

Tutto ciò è giustificato solo se si sta andando a fare qualche ricerca per l'elaborazione pesante.Se avete solo bisogno di uscita una volta ordinati per frequenza, allora si può solo produrre un elenco di (anonimo) tuple:

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

O per divertimento si potrebbe usare un po ' di estensione LINQ bontà:

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

Ordinare i valori

Questo mostra come ordinare i valori in un Dizionario.Vediamo un programma di console è possibile compilare in Visual Studio e l'esecuzione.Si aggiunge chiavi di un Dizionario e poi li ordina in base alla loro valori.Ricordate che il Dizionario istanze non sono inizialmente ordinati in alcun modo.Usiamo il LINQ orderby parola chiave in una istruzione di query.

La Clausola OrderBy Programma che ordina Dizionario [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;
    }
}

Uscita

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

L'ordinamento di una SortedDictionary elenco di legare in un ListView controllo 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:

<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>

Il modo più semplice per ottenere un ordinato Dizionario di utilizzare il costruito nel SortedDictionary classe:

//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 contiene la versione ordinata di sections

Le altre risposte sono buone, se si vuole avere una "temporanea" lista ordinata per Valore.Tuttavia, se si desidera avere un dizionario ordinato per Key che sincronizza automaticamente con un altro dizionario, che è ordinato per Value, si potrebbe utilizzare il Bijection<K1, K2> classe.

Bijection<K1, K2> consente di inizializzare la collezione con due dizionari, quindi, se volete uno di loro ad essere ordinati, e si desidera che l'altro per essere ordinati, si potrebbe creare il tuo biiezione con il seguente codice

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

È possibile utilizzare dict come con un normale dizionario (implementa IDictionary<K, V>), e quindi chiamare dict.Inverse per ottenere il "inversa" dizionario che è ordinato per Value.

Bijection<K1, K2> è parte di Loyc.Collections.dll, ma se si desidera, si può semplicemente copiare e incollare il il codice sorgente nel proprio progetto.

Nota:Nel caso In cui non ci sono più chiavi con lo stesso valore, non è possibile utilizzare Bijection, ma si potrebbe sincronizzare manualmente tra un comune Dictionary<Key,Value> e un BMultiMap<Value,Key>.

Supponiamo di avere un dizionario

   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) è possibile utilizzare 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);
        }

In realtà in C#, Dizionari forza avere sort() metodi, come si sono più interessati a ordinare i valori, cant ottenere i valori fino a quando si forniscono loro chiave, in breve, è necessario scorrere attraverso di loro, utilizzando LINQ dell'Ordine,

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
}

si può fare un trucco,

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

o

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

la sua dipendono anche da che tipo di valori da memorizzare,
è unico (come string, int) o più (come la Lista, Array, classe definita dall'utente),
se il singolo si può fare l'elenco di esso e poi applicare un ordinamento.
se la classe definita dall'utente, poi che la classe deve implementare IComparable,
ClassName: IComparable<ClassName> e sovrascrivere compareTo(ClassName c) quanto sono più veloci di LINQ, e più orientato.

È possibile ordinare il Dizionario di valore e ottenere il risultato in dizionario utilizzando il codice riportato di seguito:

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

Dato che si dispone di un dizionario è possibile ordinare direttamente i valori di utilizzo al di sotto di una linea:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top