¿Cómo se ordena un diccionario por valor?

A menudo tengo que ordenar un diccionario, que consta de claves y valores, por valor. Por ejemplo, tengo un hash de palabras y frecuencias respectivas, que quiero ordenar por frecuencia.

Hay una SortedList que es buena para un valor único (por ejemplo, frecuencia), que quiero asignar a la palabra.

ClasificadosDiccionario ordena por clave, no por valor. Algunos recurren a una clase personalizada , pero ¿hay una manera más limpia?

Utilizar:

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

Dado que tiene como objective .NET 2.0 o superior, puede simplificar esto en syntax lambda; es equivalente, pero más corto. Si tiene como objective .NET 2.0, solo puede usar esta syntax si está utilizando el comstackdor de Visual Studio 2008 (o superior).

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

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

Esto también permitiría una gran flexibilidad, ya que puede seleccionar los 10 mejores, 20 10%, etc. O si está usando su índice de frecuencia de palabras para StartsWith type-ahead , también podría incluir la cláusula StartsWith .

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

Mirando a su alrededor y usando algunas características de C # 3.0 podemos hacer esto:

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

Esta es la manera más limpia que he visto y es similar a la forma Ruby de manejar hashes.

Puede ordenar un diccionario por valor y guardarlo de nuevo en sí mismo (de modo que cuando llegue al límite, los valores salgan en orden):

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

Claro, puede no ser correcto, pero funciona.

En un nivel alto, no tiene otra opción que recorrer el diccionario completo y observar cada valor.

Tal vez esto ayude: http://bytes.com/forum/thread563638.html Copiar / pegar de 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); } ); 

Nunca serás capaz de ordenar un diccionario de todos modos. En realidad no están ordenados. Las garantías para un diccionario son que las colecciones de claves y valores son iterables, y los valores se pueden recuperar por índice o clave, pero aquí no hay garantía de ningún orden en particular. Por lo tanto, necesitaría obtener el par de nombre y valor en una lista.

No ordena las entradas en el Diccionario. La clase de diccionario en .NET se implementa como una tabla hash; esta estructura de datos no se puede ordenar por definición.

Si necesita poder iterar sobre su colección (por clave), debe utilizar SortedDictionary, que se implementa como un Árbol de búsqueda binaria.

En su caso, sin embargo, la estructura fuente es irrelevante, porque está ordenada por un campo diferente. Debería ordenarlo por frecuencia y colocarlo en una nueva colección ordenada por el campo correspondiente (frecuencia). Entonces, en esta colección, las frecuencias son claves y las palabras son valores. Como muchas palabras pueden tener la misma frecuencia (y vas a usarla como clave), no puedes usar ni Dictionary ni SortedDictionary (requieren claves únicas). Esto te deja con una SortedList.

No entiendo por qué insistes en mantener un enlace al elemento original en tu diccionario principal / primero.

Si los objetos en su colección tuvieran una estructura más compleja (más campos) y necesitara poder acceder / clasificarlos de manera eficiente utilizando varios campos diferentes como claves – Probablemente necesite una estructura de datos personalizada que consistiría en el almacenamiento principal que admite O (1) inserción y eliminación (LinkedList) y varias estructuras de indexación – Dictionaries / SortedDictionaries / SortedLists. Estos índices utilizarían uno de los campos de su clase compleja como una clave y un puntero / referencia al LinkedListNode en LinkedList como valor.

Tendría que coordinar las inserciones y eliminaciones para mantener sus índices sincronizados con la colección principal (LinkedList) y las extracciones serían bastante caras, creo. Esto es similar a cómo funcionan los índices de bases de datos: son fantásticos para las búsquedas, pero se convierten en una carga cuando necesita realizar muchas operaciones de inserción y eliminación.

Todo lo anterior solo está justificado si va a hacer un procesamiento pesado de búsqueda. Si solo necesita enviarlos una vez ordenados por frecuencia, entonces podría generar una lista de tuplas (anónimas):

 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 por diversión, podrías usar algunas bondades de extensión 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)); 

Ordenar valores

Esto muestra cómo ordenar los valores en un diccionario. Vemos un progtwig de consola que puede comstackr en Visual Studio y ejecutar. Agrega claves a un diccionario y luego las ordena por sus valores. Recuerde que las instancias de diccionario no están inicialmente ordenadas de ninguna manera. Usamos la palabra clave LINQ orderby en una statement de consulta.

Progtwig OrderBy Clause que ordena el diccionario [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; } } 

Salida

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

Ordenando una lista SortedDictionary para enlazar a un control ListView usando 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:

         

La forma más fácil de obtener un diccionario ordenado es usar la clase 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 contendrá la versión ordenada de las sections

Las otras respuestas son buenas, si lo único que desea es tener una lista “temporal” ordenada por Valor. Sin embargo, si desea tener un diccionario ordenado por Key que se sincronice automáticamente con otro diccionario ordenado por Value , puede usar la Bijection .

Bijection permite inicializar la colección con dos diccionarios existentes, por lo tanto, si desea que uno de ellos no esté ordenado, y desea que el otro esté ordenado, puede crear su bijection con un código como

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

Puede usar dict como cualquier diccionario normal (implementa IDictionary<> ) y luego llamar a dict.Inverse para obtener el diccionario “inverso” que está ordenado por Value .

Bijection es parte de Loyc.Collections.dll , pero si lo desea, puede simplemente copiar el código fuente en su propio proyecto.

Nota : En caso de que haya varias claves con el mismo valor, no puede usar Bijection , pero puede sincronizar manualmente entre un Dictionary y un BMultiMap .

Supongamos que tenemos un diccionario como

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

Puede ordenar el diccionario por valor y obtener el resultado en el diccionario usando el siguiente código:

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

Dado que tiene un diccionario, puede ordenarlos directamente en los valores que se encuentran debajo de un trazador de líneas:

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