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 solo valor (por ejemplo, frecuencia), que quiero asignar de nuevo a la palabra.
Ordenes ordenadas por clave, no por valor. Algunos recurren a una clase personalizada , pero ¿hay una forma más limpia?
c#
.net
sorting
dictionary
Kalid
fuente
fuente
IComparer
que haga el truco (es cierto que acepta una clave para comparar, pero con una clave, puede obtener un valor). ;-)Respuestas:
Utilizar:
Como está apuntando a .NET 2.0 o superior, puede simplificar esto en sintaxis lambda: es equivalente, pero más corto. Si está apuntando a .NET 2.0, solo puede usar esta sintaxis si está usando el compilador de Visual Studio 2008 (o superior).
fuente
myList.Sort((x,y)=>x.Value.CompareTo(y.Value));
IEnumerable
, por lo que pueden obtener una lista ordenada como esta:var mySortedList = myDictionary.OrderBy(d => d.Value).ToList();
Use LINQ:
Esto también permitiría una gran flexibilidad, ya que puede seleccionar los 10 mejores, 20 10%, etc. O si está utilizando su índice de frecuencia de palabras para
type-ahead
, también podría incluir unaStartsWith
cláusula.fuente
IEnumerable<KeyValuePair<TKey, TValue>>
o anOrderedDictionary<TKey, TValue>
. O uno debería usar unSortedDictionary
desde el principio. Para un plano,Dictionary
el MSDN establece claramente "El orden en que se devuelven los elementos no está definido". Parece que la última edición de @ rythos42 es la culpable. :).ToDictionary
- los diccionarios estándar no garantizan un orden de clasificaciónfuente
Mirando a nuestro alrededor y usando algunas características de C # 3.0 podemos hacer esto:
Esta es la forma más limpia que he visto y es similar a la forma Ruby de manejar hashes.
fuente
(for KeyValuePair<string, int> item in keywordCounts.OrderBy(key => key.Value) select item).ToDictionary(t => t.Key, t => t.Value)
- solo una pequeña adición a tu respuesta :) Gracias, por cierto :)Puede ordenar un Diccionario por valor y guardarlo de nuevo en sí mismo (de modo que cuando lo lea por encima los valores salgan en orden):
Claro, puede que no sea correcto, pero funciona.
fuente
En un nivel alto, no tiene otra opción que recorrer todo el Diccionario y observar cada valor.
Tal vez esto ayude: http://bytes.com/forum/thread563638.html Copiar / Pegar de John Timney:
fuente
Nunca podrías ordenar un diccionario de todos modos. En realidad no están ordenados. Las garantías para un diccionario son que las colecciones de clave y valor son iterables, y los valores se pueden recuperar por índice o clave, pero no hay garantía de ningún orden en particular. Por lo tanto, necesitaría obtener el par de valor de nombre en una lista.
fuente
No ordena 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 usar SortedDictionary, que se implementa como un árbol de búsqueda binario.
En su caso, sin embargo, la estructura fuente es irrelevante, ya que está ordenada por un campo diferente. Aún necesitaría ordenarlo por frecuencia y colocarlo en una nueva colección ordenada por el campo relevante (frecuencia). Entonces, en esta colección, las frecuencias son claves y las palabras son valores. Dado que muchas palabras pueden tener la misma frecuencia (y la va a usar como una clave), no puede usar ni Dictionary ni SortedDictionary (requieren claves únicas). Esto te deja con una SortedList.
No entiendo por qué insiste en mantener un enlace al elemento original en su diccionario principal / primer.
Si los objetos en su colección tuvieran una estructura más compleja (más campos) y necesitara poder acceder / ordenarlos eficientemente usando varios campos diferentes como claves, probablemente necesitaría una estructura de datos personalizada que consistiría en el almacenamiento principal que admite la inserción y eliminación de O (1) (LinkedList) y varias estructuras de indexación: Diccionarios / SortedDictionaries / SortedLists. Estos índices utilizarían uno de los campos de su clase compleja como 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 eliminaciones serían bastante caras, creo. Esto es similar a cómo funcionan los índices de base de datos: son fantásticos para las búsquedas, pero se convierten en una carga cuando necesita realizar muchas inserciones y eliminaciones.
Todo lo anterior solo se justifica si va a realizar un procesamiento pesado de búsqueda. Si solo necesita generarlos una vez ordenados por frecuencia, entonces podría producir una lista de tuplas (anónimas):
fuente
fuente
O por diversión, podría usar algunas bondades de extensión LINQ:
fuente
Ordenar una
SortedDictionary
lista para enlazar en unListView
control usando VB.NET:XAML:
fuente
La forma más fácil de obtener un diccionario ordenado es usar la
SortedDictionary
clase integrada :sortedSections
will contiene la versión ordenada desections
fuente
SortedDictionary
ordena por teclas. El OP quiere ordenar por valor.SortedDictionary
No ayuda en este caso.sorteddictionary()
siempre gané al menos 1 microsegundo, y es mucho más fácil de administrar (ya que la sobrecarga de convertirlo nuevamente en algo que interactúa y se maneja de manera similar a un Diccionario es 0 (ya es asorteddictionary
)).Las otras respuestas son buenas, si todo lo que quiere es tener una lista "temporal" ordenada por Valor. Sin embargo, si desea ordenar un diccionario
Key
que se sincronice automáticamente con otro diccionario ordenadoValue
, puede usar laBijection<K1, K2>
clase .Bijection<K1, K2>
le permite inicializar la colección con dos diccionarios existentes, por lo que si desea que uno de ellos no esté ordenado y desea que el otro esté ordenado, puede crear su biyección con un código comoPuede usarlo
dict
como cualquier diccionario normal (se implementaIDictionary<K, V>
) y luego llamardict.Inverse
para obtener el diccionario "inverso" que se ordena porValue
.Bijection<K1, K2>
es parte de Loyc.Collections.dll , pero si lo desea, simplemente puede copiar el código fuente en su propio proyecto.Nota : En caso de que haya varias claves con el mismo valor, no puede usarlas
Bijection
, pero podría sincronizar manualmente entre una ordinariaDictionary<Key,Value>
y unaBMultiMap<Value,Key>
.fuente
Supongamos que tenemos un diccionario como
1) puedes usar
temporary dictionary to store values as
:fuente
En realidad, en C #, los diccionarios no tienen métodos sort (), ya que está más interesado en ordenar por valores, no puede obtener valores hasta que les proporcione la clave, en resumen, necesita iterar a través de ellos, utilizando Ordenar por de LINQ,
puedes hacer un truco
o
también depende de qué tipo de valores esté almacenando,
ya sea individual (como string, int) o múltiple (como List, Array, clase definida por el usuario),
si solo puede hacer una lista, aplique el orden.
si es una clase definida por el usuario, entonces esa clase debe implementar IComparable
ClassName: IComparable<ClassName>
y anular,compareTo(ClassName c)
ya que son más rápidos que LINQ y están más orientados a objetos.fuente
Espacio de nombres requerido:
using System.Linq;
Ordenar por desc:
Ordenar por Asc:
fuente
Puede ordenar el Diccionario por valor y obtener el resultado en el diccionario usando el código a continuación:
fuente
Dado que tiene un diccionario, puede ordenarlos directamente en valores usando debajo de un trazador de líneas:
fuente