Pregunta

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

Hay un SortedList que es bueno para un único valor (es decir la frecuencia), que quiero mapa de nuevo a la palabra.

SortedDictionary pedidos por clave, no de valor.Algunos recurren a un clase personalizada, pero hay un modo más limpio?

¿Fue útil?

Solución

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

Puesto que usted está apuntando .NET 2.0 o superior, se puede simplificar esta en lambda sintaxis -- es equivalente, pero más corto.Si usted está apuntando .NET 2.0 sólo puede utilizar esta sintaxis si usted está utilizando el compilador de Visual Studio 2008 (o por encima).

var myList = aDictionary.ToList();

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

Otros consejos

El uso de 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 en el que puede seleccionar el top 10 20 10%, etc.O si usted está utilizando su palabra índice de frecuencia para type-ahead, también podría incluir StartsWith cláusula así.

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

Mirando a su alrededor, y usando un poco de C# 3.0 características que nos pueden hacer esto:

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

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

Usted puede ordenar un Diccionario de valor y volver a guardarlo para sí mismo (de modo que cuando usted foreach sobre ella los valores que salen en orden):

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

Claro, puede no ser correcta, pero funciona.

En un alto nivel, que no tienen otra opción, a continuación, caminar a través de todo el Diccionario y buscar en cada valor.

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

Nunca sería capaz de ordenar un diccionario de todos modos.En realidad no son solicitados.Las garantías para un diccionario que la clave y el valor de las colecciones son iterable, y los valores pueden ser recuperada por el índice o clave, pero no hay ninguna garantía de ningún orden en particular.Por lo tanto, usted necesita para obtener el par de nombre y valor en una lista.

No ordenar las entradas en el Diccionario.Diccionario de clase .NET es implementado como una tabla hash - esta estructura de datos no es ordenable por definición.

Si usted necesita para ser capaz de recorrer más de su colección (clave) - es necesario utilizar SortedDictionary, que se implementa como un Árbol de Búsqueda Binario.

En su caso, sin embargo, la estructura de origen es irrelevante, porque es ordenada por un campo diferente.Aún se necesita ordenar por frecuencia y la puso en una nueva colección ordenada por el campo correspondiente (frecuencia).Así, en esta colección las frecuencias son las claves y las palabras son los valores.Dado que muchas de las palabras que pueden tener la misma frecuencia (y que se va a utilizar como clave) usted no puede usar ni Diccionario ni SortedDictionary (que requieren de claves únicas).Esto te deja con una SortedList.

No entiendo por qué insisten en el mantenimiento de un enlace a la noticia original en su principal/primer diccionario.

Si los objetos en su colección había una estructura más compleja (más campos) y usted necesita para ser capaz de acceder eficientemente a/ordenarlos mediante diferentes campos como claves - Que probablemente se necesitará una estructura de datos personalizada que consiste en el almacenamiento principal que soporta O(1) inserción y extracción (LinkedList) y varias estructuras de indexación - Diccionarios/SortedDictionaries/SortedLists.Estos índices se podría utilizar uno de los campos de la clase complejo como una clave y un puntero o referencia a la LinkedListNode en el LinkedList como un valor.

Usted necesidad de coordinar las inserciones y eliminaciones para mantener sus índices en sintonía con la colección principal (LinkedList) y absorciones sería bastante caro, me lo pensaría.Esto es similar a cómo los índices de base de datos de trabajo - son fantásticas para las búsquedas, pero se convierten en una carga cuando es necesario realizar muchos insetions y eliminaciones.

Todo lo anterior sólo se justifica si vas a hacer algún look-up procesamiento pesado.Si sólo necesita una salida, una vez ordenados por frecuencia, a continuación, sólo podría producir una lista de (anónimo) tuplas:

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 para la diversión que usted podría utilizar un poco de LINQ extensión de la 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));

Ordenar los valores de

Este espectáculo de cómo ordenar los valores en un Diccionario.Vemos un programa de consola, puede compilar en Visual Studio y ejecutar.Agrega claves de un Diccionario y, a continuación, ordena por sus valores.Recordar que el Diccionario de los casos, no clasificadas inicialmente en forma alguna.Utilizamos el LINQ orderby palabra clave en una instrucción de consulta.

Cláusula OrderBy Programa 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

La clasificación de un SortedDictionary lista para enlazar en un ListView control de uso 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 forma más sencilla de obtener un criterio de Diccionario es utilizar el construido en el SortedDictionary 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 se contiene la versión ordenada de sections

Las otras respuestas son buenas, si lo que quieres es tener un "temporal" lista ordenada por Valor.Sin embargo, si usted quiere tener un diccionario ordenados por Key que sincroniza automáticamente con otro diccionario que se ordena por Value, usted podría utilizar la Bijection<K1, K2> clase.

Bijection<K1, K2> permite inicializar la colección con dos de los diccionarios existentes, así que si quieres uno de ellos sin clasificar, y desea que el otro para ser ordenados, se podría crear un bijection con un código como

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

Puede utilizar dict como cualquier diccionario (que implementa IDictionary<K, V>) y, a continuación, llamar a dict.Inverse para obtener la "inversa" diccionario de la cual se ordena por Value.

Bijection<K1, K2> es parte de Loyc.Collections.dll, pero si usted quiere, usted puede simplemente copiar el código fuente en su propio proyecto.

Nota:En el caso de que existan varias claves con el mismo valor, no se puede usar Bijection, pero usted puede sincronizar manualmente entre una simple Dictionary<Key,Value> y un BMultiMap<Value,Key>.

Supongamos que tenemos un diccionario

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

De hecho en C#, Diccionarios dint han sort() los métodos, como usted está más interesado en ordenar por valores, usted no puede obtener los valores hasta que proporcione la clave, en pocas palabras, usted necesita para iterar a través de ellos, el uso de LINQ Pedido,

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
}

usted puede hacer un truco,

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

o

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

también depende de qué tipo de valores que se van a almacenar,
es único (como string, int) o múltiples (como Lista, Matriz, definida por el usuario),
si solo puedes hacer la lista de la misma, a continuación, aplicar especie.
si el usuario define la clase, luego de que la clase debe implementar IComparable,
ClassName: IComparable<ClassName> y reemplazar compareTo(ClassName c) como ellos son más rápidos que LINQ, y más orientado a objetos.

Usted puede ordenar el Diccionario de valor y obtener el resultado en el diccionario utilizando el siguiente código:

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

Dado que hay un diccionario se puede ordenar directamente en los valores de uso por debajo de una línea:

var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top