¿Cómo se ordena un diccionario por valor?

votos
671

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 SortedListque es buena para un solo valor (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?

Publicado el 02/08/2008 a las 01:40
fuente por usuario
En otros idiomas...                            


18 respuestas

votos
148

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

foreach (KeyValuePair<string,int> 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.

Respondida el 02/08/2008 a las 01:43
fuente por usuario

votos
56

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<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);
    }
);
Respondida el 02/08/2008 a las 01:47
fuente por usuario

votos
459

Utilizar:

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

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

var myList = aDictionary.ToList();

myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
Respondida el 02/08/2008 a las 02:15
fuente por usuario

votos
473

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

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

Respondida el 04/08/2008 a las 16:22
fuente por usuario

votos
22

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.

Respondida el 19/12/2008 a las 23:47
fuente por usuario

votos
5

La forma más fácil de conseguir un diccionario ordenados es utilizar el construido en SortedDictionaryla clase:

//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 voluntad contiene la versión ordenada de sections

Respondida el 02/04/2010 a las 23:36
fuente por usuario

votos
9

Ordenar una SortedDictionarylista de obligar a un ListViewcontrol 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:

<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>
Respondida el 23/04/2010 a las 10:36
fuente por usuario

votos
10

O por diversión que podría utilizar alguna extensión LINQ bondad:

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));
Respondida el 30/06/2010 a las 12:12
fuente por usuario

votos
179
var ordered = dict.OrderBy(x => x.Value);
Respondida el 11/11/2010 a las 18:16
fuente por usuario

votos
140

Puede ordenar un diccionario por su valor y volver a guardarlo en sí mismo (de modo que cuando se forEach sobre ella los valores salen en orden):

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

Está claro que no puede ser correcto, pero funciona.

Respondida el 22/06/2011 a las 11:26
fuente por usuario

votos
10

ordenar los valores

Esto muestra cómo ordenar los valores de un diccionario. Vemos un programa de consola se puede compilar en Visual Studio y correr. Se agrega claves de un diccionario y luego los ordena por sus valores. Recuerde que diccionario casos no se ordenan inicialmente en modo alguno. Utilizamos la palabra clave OrdenarPor LINQ en una instrucción de consulta.

Programa Cláusula OrdenarPor que ordena Diccionario [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;
    }
}

Salida

dog: 0
cat: 1
programmer: 2
eel: 3
mouse: 5
Respondida el 20/07/2012 a las 10:49
fuente por usuario

votos
-2

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

Dictionary <<string, string>> ShareUserNewCopy = 
       ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
                                                        pair => pair.Value);                                          
Respondida el 24/07/2012 a las 13:24
fuente por usuario

votos
16

No es ordenar las entradas en el diccionario. Diccionario de clases en .NET se implementa como una tabla hash - esta estructura de datos no se puede ordenar por definición.

Si tiene que ser capaz de recorrer más de su colección (con llave) - es necesario utilizar SortedDictionary, que se implementa como un árbol binario de búsqueda.

En su caso, sin embargo, la estructura de la fuente es irrelevante, ya que está ordenada por un campo diferente. Usted todavía necesita para solucionar el problema por la frecuencia y ponerlo en una nueva colección ordenados por el campo correspondiente (frecuencia). Así que en esta colección son las frecuencias claves y las palabras son valores. Dado que muchas palabras pueden tener la misma frecuencia (y que se va a utilizar como una llave) no se puede utilizar ni el diccionario ni SortedDictionary (que requieren claves únicas). Esto le deja con un SortedList.

No entiendo por qué insistes en mantener un enlace al artículo original en su primer diccionario principal /.

Si los objetos en su colección tenían una estructura más compleja (más campos) y que tenían que ser capaces de manera eficiente el acceso / ordenarlos utilizando varios campos diferentes como claves - Es probable que se necesite una estructura de datos a medida que consistiría en la memoria principal que se apoya O (1) de inserción y de extracción (LinkedList) y varias estructuras de indexación - Diccionarios / SortedDictionaries / SortedLists. Estos índices se utilice uno de los campos de su clase de complejo como una llave y un puntero / referencia a la LinkedListNode en el ListaEnlazada como un valor.

Lo que se necesita para coordinar las inserciones y eliminaciones para mantener sus índices en sincronía con la colección principal (LinkedList) y el traslado sería bastante caro que lo pensaría. Esto es similar a cómo funcionan los índices de bases de datos - que son fantásticos para las búsquedas, sino que se conviertan en una carga cuando es necesario realizar muchas insetions y supresiones.

Todo lo anterior sólo se justifica si se va a hacer algo de procesamiento pesado de consulta. Si sólo necesita salida de ellos, una vez ordenadas según la frecuencia a continuación, usted podría producir una lista de tuplas (anónimo):

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);
}
Respondida el 13/12/2012 a las 07:19
fuente por usuario

votos
-2

Teniendo en cuenta que tiene un diccionario puede ordenar directamente en valores utilizando un trazador de líneas más abajo:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Respondida el 31/05/2014 a las 23:30
fuente por usuario

votos
4

Supongamos que tenemos un diccionario como

   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) que puede utilizar 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);
        }
Respondida el 02/02/2015 a las 10:46
fuente por usuario

votos
12
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Respondida el 20/07/2015 a las 11:01
fuente por usuario

votos
5

Las otras respuestas son buenas, si todo lo que quiere es tener una lista de "temporal" ordenados por valor. Sin embargo, si usted quiere tener un diccionario ordenado por Keyque se sincroniza automáticamente con otro diccionario que está ordenada por Value, podría utilizar la Bijection<K1, K2>clase .

Bijection<K1, K2> permite inicializar la colección con dos diccionarios existentes, por lo que si quieres uno de ellos a ser sin clasificar, y desea que el otro para ser ordenada, puede crear su biyección con el código como

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

Se puede utilizar dictcomo cualquier diccionario normal (que implementa IDictionary<>), y luego llamar dict.Inversepara obtener el diccionario "inversa", que está ordenada por Value.

Bijection<K1, K2>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 se puede utilizar Bijection, pero se puede sincronizar manualmente entre una ordinaria Dictionary<Key,Value>y una BMultiMap<Value,Key>.

Respondida el 26/02/2016 a las 04:15
fuente por usuario

votos
0

En realidad, en C #, Diccionarios fuerza tiene sort () métodos, ya que está más interesado en ordenar por valores, no puede obtener valores hasta que se les proporcione clave, en definitiva, es necesario iterar a través de ellos, el uso de LINQ de ORDER BY

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
}

que puede hacer un truco,

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

o

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

su también dependen de qué tipo de valores que se está almacenando,
es lo único (como string, int) o múltiple (como Lista, Array, clase definida por el usuario),
si solo se puede hacer lista de los que a continuación se aplica una especie.
si el usuario define la clase, entonces esa clase debe implementar IComparable,
ClassName: IComparable<ClassName>y anular compareTo(ClassName c) ya que son más rápido que LINQ, y más orientada objeto.

Respondida el 26/02/2019 a las 12:39
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more