¿Cómo clasifico un diccionario por valor?


3422

Tengo un diccionario de valores leídos de dos campos en una base de datos: un campo de cadena y un campo numérico. El campo de cadena es único, por lo que esa es la clave del diccionario.

Puedo ordenar las claves, pero ¿cómo puedo ordenar según los valores?

Nota: He leído la pregunta de desbordamiento de pila aquí. ¿Cómo clasifico una lista de diccionarios por un valor del diccionario? y probablemente podría cambiar mi código para tener una lista de diccionarios, pero dado que realmente no necesito una lista de diccionarios, quería saber si hay una solución más simple para ordenar en orden ascendente o descendente.


99
La estructura de datos del diccionario no tiene un orden inherente. Puede recorrerlo pero no hay nada que garantice que la iteración seguirá un orden en particular. Esto es por diseño, por lo que su mejor opción es, probablemente, utilizar una estructura de datos antro para la representación.
Daishiman

135
"sorted ()" puede operar en diccionarios (y devuelve una lista de claves ordenadas), por lo que creo que él está al tanto de esto. Sin conocer su programa, es absurdo decirle a alguien que está usando la estructura de datos incorrecta. Si las búsquedas rápidas son lo que necesita el 90% del tiempo, entonces probablemente lo que quiere es un dict.
bobpaul

Las tres salidas (claves, valores, ambos) para ordenar los diccionarios están cubiertas aquí en un estilo claro y conciso: stackoverflow.com/questions/16772071/sort-dict-by-value-python
JStrahl

2
@Daishiman La clase base puede no estar ordenada pero OrderedDict es, por supuesto.
Taylor Edmiston

1
En Python 3.6+ los diccionarios conservan el orden de inserción. Esto, por supuesto, no es lo mismo que la posibilidad de ordenarlos por valor, pero por otro lado ya no es válido decir que "la estructura de datos del diccionario no tiene un orden inherente".
Konrad Kocik

Respuestas:


4956

Python 3.6+

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
{k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

Python más viejo

No es posible ordenar un diccionario, solo obtener una representación de un diccionario que está ordenado. Los diccionarios son inherentemente sin orden, pero otros tipos, como listas y tuplas, no lo son. Por lo tanto, necesita un tipo de datos ordenado para representar los valores ordenados, que será una lista, probablemente una lista de tuplas.

Por ejemplo,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_xhabrá una lista de tuplas ordenadas por el segundo elemento en cada tupla. dict(sorted_x) == x.

Y para aquellos que deseen ordenar las claves en lugar de los valores:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

En Python3 ya que no está permitido desempacar [1] podemos usar

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])

Si desea la salida como un dict, puede usar collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)

43
para horarios en varios diccionarios ordenados
Gregg Lind el

164
sorted_x.reverse()le dará un orden descendente (por el segundo elemento de tupla)
saidimu apale

414
saidimu: Como ya estamos usando sorted(), es mucho más eficiente pasar el reverse=Trueargumento.
rmh

121
En python3 he usado un lambda: sorted(d.items(), key=lambda x: x[1]). ¿Funcionará esto en python 2.x?
Keyo

84
OrderedDict agregado a las colecciones en 2.7. Ejemplo de clasificación mostrado en: docs.python.org/library/…
monkut

1264

Tan simple como: sorted(dict1, key=dict1.get)

Bueno, en realidad es posible hacer un "ordenar por valores de diccionario". Recientemente tuve que hacer eso en un código de golf (pregunta de desbordamiento de pila de código de golf: tabla de frecuencia de palabras ). En resumen, el problema era del mismo tipo: dado un texto, cuente con qué frecuencia se encuentra cada palabra y muestre una lista de las palabras principales, ordenadas por frecuencia decreciente.

Si construye un diccionario con las palabras como claves y el número de apariciones de cada palabra como valor, simplifique aquí como:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
    d[w] += 1

entonces puede obtener una lista de las palabras, ordenadas por frecuencia de uso con sorted(d, key=d.get): la ordenación itera sobre las teclas del diccionario, utilizando el número de apariciones de palabras como una clave de ordenación.

for w in sorted(d, key=d.get, reverse=True):
    print(w, d[w])

Estoy escribiendo esta explicación detallada para ilustrar lo que la gente a menudo quiere decir con "puedo ordenar fácilmente un diccionario por clave, pero ¿cómo puedo ordenarlo por valor?", Y creo que la publicación original estaba tratando de abordar ese problema. Y la solución es hacer una especie de lista de claves, basada en los valores, como se muestra arriba.


32
Esto también es bueno, pero key=operator.itemgetter(1)debería ser más escalable para la eficiencia quekey=d.get
smci

3
@raylu Observo un comportamiento de "no funciona" usando itemgetter: ----- from operator import itemgetter d = {"a":7, "b":1, "c":5, "d":3} sorted_keys = sorted(d, key=itemgetter, reverse=True) for key in sorted_keys: print "%s: %d" % (key, d[key]) ----- -> b: 1 c: 5 a: 7 d: 3 Los resultados cambian cada vez que ejecuto el código: extraño . (lo siento, no se puede mostrar el código correctamente)
bli

12
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True)y for key, val in sorted_keys: print "%s: %d" % (key, val)- itemgetter crea una función cuando se llama, no la usa directamente como en su ejemplo. Y una iteración simple en un dict usa las claves sin los valores
Izkata

18
He venido del futuro para contarte collections.Counter, que tiene un most_commonmétodo que podría interesarte :)
Eevee

2
@Eevee: existe el riesgo de ser malentendido en comentarios cortos que no sean f2f. Dato sorprendente: collections.Counterse agregó en 2.7, que se lanzó hace casi exactamente 7 años. (No lo sabía entonces, además lo habría evitado en el golf de código con el propósito de brevedad, que es la única obsesión del juego)
Nas Banov

859

Podrías usar:

sorted(d.items(), key=lambda x: x[1])

Esto ordenará el diccionario por los valores de cada entrada dentro del diccionario de menor a mayor.

Para ordenarlo en orden descendente solo agregue reverse=True:

sorted(d.items(), key=lambda x: x[1], reverse=True)

Entrada:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

Salida:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]

Por lo que he visto ( docs.python.org/2/library/… ), hay una clase llamada OrderedDict que se puede ordenar y mantener el orden sin dejar de ser un diccionario. De los ejemplos de código, puede usar lambda para ordenarlo, pero no lo he probado personalmente: P
UsAndRufus

53
Prefiero key=lambda (k, v): vpersonalmente
Claudiu

35
@Claudiu También me gusta esa (k, v)sintaxis, pero no está disponible en Python 3, donde se eliminó el desempaquetado de parámetros de tupla .
Bob Stein

2
dict(sorted(d.items(), key=lambda x: x[1])).
Dr_Hope

3
No. crear un dict a partir de una lista ordenada de tuplas mata el orden nuevamente ...
Jean-François Fabre

233

Los dictados no se pueden ordenar, pero puede crear una lista ordenada a partir de ellos.

Una lista ordenada de valores dict:

sorted(d.values())

Una lista de pares (clave, valor), ordenados por valor:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

¿En qué orden se colocan las claves con el mismo valor? Primero ordené la lista por claves, luego por valores, pero el orden de las claves con el mismo valor no permanece.
SabreWolfy

1
Los dictados ahora se pueden ordenar, comenzando con CPython 3.6 y todas las demás implementaciones de Python que comienzan con 3.7
Boris

161

En Python 2.7 reciente, tenemos el nuevo tipo OrderedDict , que recuerda el orden en que se agregaron los elementos.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

Para hacer un nuevo diccionario ordenado del original, ordenando por los valores:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

El OrderedDict se comporta como un dict normal:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

55
No se trata de esto, no se trata de mantener el orden de las teclas, sino de "ordenar por valor"
Nas Banov

10
@Nas Banov: NO está ordenando por la clave. Se está ordenando en el orden, creamos los artículos. En nuestro caso, ordenamos por el valor. desafortunadamente, el dict de 3 elementos fue elegido desafortunadamente por lo que el orden era el mismo, cuando se ordenó voth por valor y clave, por lo que amplié el dict de muestra.
mykhal

sorted(d.items(), key=lambda x: x[1])¿Puedes explicar qué xsignifica, por qué puede llevar x[1]a lambda? ¿Por qué no puede ser x[0]? ¡Muchas gracias!
JZAU

1
@Boern d.items()devuelve un contenedor de (key, value)tuplas en forma de lista. [0]accede al primer elemento de la tupla, la clave, y [1]accede al segundo elemento, el valor.
BallpointBen

2
Nota: A partir de 3,6 (como un detalle de implementación CPython / PyPy) ya partir de 3,7 (como garantía lenguaje Python), llanura dictes la inserción ordenó así, por lo que sólo se puede reemplazar OrderedDictcon el dictcódigo que se ejecuta en Python moderna. OrderedDictya no es realmente necesario a menos que necesite reorganizar el orden de un existente dict(con move_to_end/ popitem) o necesite comparaciones de igualdad para ser sensible al orden. Utiliza mucha más memoria que la simple dict, por lo que si puede, dictes el camino a seguir.
ShadowRanger

104

ACTUALIZACIÓN: 5 DE DICIEMBRE DE 2015 usando Python 3.5

Si bien encontré útil la respuesta aceptada, también me sorprendió que no se haya actualizado para hacer referencia a OrderedDict desde el módulo de colecciones de biblioteca estándar como una alternativa viable y moderna, diseñada para resolver exactamente este tipo de problema.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

La documentación oficial de OrderedDict también ofrece un ejemplo muy similar, pero utilizando una lambda para la función de clasificación:

# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

86

Más o menos lo mismo que la respuesta de Hank Gay :

sorted([(value,key) for (key,value) in mydict.items()])

O optimizado ligeramente como lo sugiere John Fouhy:

sorted((value,key) for (key,value) in mydict.items())

99
..y como con la respuesta de Hank Gay, no necesitas los corchetes. sorted () felizmente tomará cualquier iterable, como una expresión generadora.
John Fouhy el

Es posible que aún necesite intercambiar los elementos de tupla (valor, clave) para terminar con la (clave, valor). Entonces se necesita otra comprensión de la lista. [(key, value) for (value, key) in sorted_list_of_tuples]
saidimu apale

no, es mejor dejar los corchetes, porque de sortedtodos modos tendrá que reconstruir la lista, y la reconstrucción desde gencomp será más rápida. Bueno para codegolfing, malo para la velocidad. Mantén la ([])versión fea .
Jean-François Fabre

75

A menudo puede ser muy útil usar namedtuple . Por ejemplo, tiene un diccionario de 'nombre' como claves y 'puntaje' como valores y desea ordenar por 'puntaje':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

ordenar primero con la puntuación más baja:

worst = sorted(Player(v,k) for (k,v) in d.items())

ordenar primero con la puntuación más alta:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

Ahora puede obtener el nombre y la puntuación de, digamos, el segundo mejor jugador (índice = 1) muy pitónicamente así:

player = best[1]
player.name
    'Richard'
player.score
    7

¿Cómo podría convertirlo de nuevo a un diccionario?
rowana

as_list = [Player (v, k) para (k, v) en d.items ()] as_dict = dict ((p.name, p.score) para p en as_list)
Remi

72

A partir de Python 3.6 , se ordenará el dict incorporado

Buenas noticias, por lo que el caso de uso original del OP de pares de mapeo recuperados de una base de datos con identificadores de cadena únicos como claves y valores numéricos como valores en un Python v3.6 + dict incorporado, ahora debe respetar el orden de inserción.

Si dice las expresiones de tabla de dos columnas resultantes de una consulta de base de datos como:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

se almacenaría en dos tuplas de Python, k_seq y v_seq (alineadas por índice numérico y con la misma longitud de curso), luego:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Permitir la salida más tarde como:

for k, v in ordered_map.items():
    print(k, v)

cediendo en este caso (¡para el nuevo dict incorporado de Python 3.6+!):

foo 0
bar 1
baz 42

en el mismo orden por valor de v.

Donde en la instalación de Python 3.5 en mi máquina actualmente produce:

bar 1
foo 0
baz 42

Detalles:

Según lo propuesto en 2012 por Raymond Hettinger (cf. mail en python-dev con asunto "Diccionarios más compactos con iteración más rápida" ) y ahora (en 2016) anunciado en un correo de Victor Stinner a python-dev con asunto "Python 3.6 dict se convierte en compacto y obtiene una versión privada, y las palabras clave se ordenan " debido a la solución / implementación del problema 27350 " Dict compacto y ordenado " en Python 3.6 ahora podremos usar un dict incorporado para mantener el orden de inserción !!

Esperemos que esto conduzca a una implementación de OrderedDict de capa delgada como primer paso. Como indicó @ JimFasarakis-Hilliard, algunos ven casos de uso para el tipo OrderedDict también en el futuro. Creo que la comunidad de Python en general inspeccionará cuidadosamente, si esto resistirá la prueba del tiempo, y cuáles serán los próximos pasos.

Es hora de repensar nuestros hábitos de codificación para no perder las posibilidades abiertas por un ordenamiento estable de:

  • Argumentos de palabras clave y
  • (intermedio) almacenamiento dict

La primera porque facilita el despacho en la implementación de funciones y métodos en algunos casos.

El segundo, ya que alienta a usar más fácilmente dicts como almacenamiento intermedio en las tuberías de procesamiento.

Raymond Hettinger proporcionó amablemente documentación que explicaba " Los Diccionarios de Tech Behind Python 3.6 " - de su presentación del Grupo Meetup de San Francisco Python 2016-DIC-08.

Y tal vez algunas páginas de preguntas y respuestas altamente decoradas de Stack Overflow recibirán variantes de esta información y muchas respuestas de alta calidad requerirán también una actualización por versión.

Caveat Emptor (pero también vea la actualización a continuación 2017-12-15):

Como @ajcr señala correctamente: "El aspecto de preservación del orden de esta nueva implementación se considera un detalle de implementación y no se debe confiar en él". (desde el whatsnew36 ) no pellizca , pero la cita fue cortada un poco pesimista ;-). Continúa como "(esto puede cambiar en el futuro, pero se desea tener esta nueva implementación de dict en el idioma durante algunos lanzamientos antes de cambiar la especificación del idioma para exigir la semántica de preservación del orden para todas las implementaciones actuales y futuras de Python; esto también ayuda a preservar la compatibilidad con versiones anteriores del lenguaje donde el orden de iteración aleatoria todavía está vigente, por ejemplo, Python 3.5) ".

Entonces, como en algunos idiomas humanos (por ejemplo, alemán), el uso da forma al idioma, y ​​la voluntad ahora se ha declarado ... en whatsnew36 .

Actualización 2017-12-15:

En un correo a la lista python-dev , Guido van Rossum declaró:

Hazlo así. "Dict mantiene orden de inserción" es el fallo. ¡Gracias!

Entonces, el efecto secundario de la versión 3.6 CPython del orden de inserción dict ahora se está convirtiendo en parte de la especificación del lenguaje (y ya no es solo un detalle de implementación). Ese hilo de correo también surgió algunos objetivos de diseño distintivos collections.OrderedDictcomo lo recordó Raymond Hettinger durante la discusión.


15
Se debe enfatizar la advertencia en la página 'whatsnew' a la que se ha vinculado: el aspecto de preservación del orden de esta nueva implementación se considera un detalle de implementación y no se debe confiar en él . Nadie debería suponer que el dicttipo respetará el orden de inserción en su código. Esto no es parte de la definición del lenguaje y la implementación podría cambiar en cualquier versión futura. Continúe utilizando OrderedDictpara garantizar el pedido.
Alex Riley

@ajcr gracias por la advertencia, muy apreciada, ya que los emoticones y los quizás se incluyeron en mi respuesta, esto debería indicar, el cambio es enorme pero, por supuesto, solo está disponible para CPython (implementación de referencia) y PyPy. Para algo completamente diferente ... Raramente hablo con detalles de no implementación cuando codifico instrucciones hombre-máquina. Si solo hubiera sido Jython ;-) ... Podría no haber tenido el coraje de escribirlo.
Dilettant

OrderedDictdefinitivamente no se caerá; en su lugar, se convertirá en un envoltorio delgado alrededor de la implementación de dict actual (por lo que puede agregar que también será más compacto). Agregar ese fragmento con el ImportErrorno es la mejor idea debido a que engaña a los lectores que OrderedDictno tiene ningún uso.
Dimitris Fasarakis Hilliard

@ JimFasarakis-Hilliard gracias por los comentarios. "Las mejores ideas" me hicieron sonreír: el futuro a menudo es difícil de predecir. Pero me gusta que su sugerencia verifique las fuentes, lo intente y luego actualice la respuesta en consecuencia. Gracias de nuevo.
Dilettant

8
@AlexRiley Esta advertencia ya no es precisa. Python3.7 garantiza diccionarios ordenados.
gerrit

42

Tuve el mismo problema y lo resolví así:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(¡Las personas que responden "No es posible ordenar un dict" no leyeron la pregunta! De hecho, "Puedo ordenar las claves, pero ¿cómo puedo ordenarlas en función de los valores?" Claramente significa que quiere una lista de las claves ordenadas según el valor de sus valores).

Tenga en cuenta que el orden no está bien definido (las claves con el mismo valor estarán en un orden arbitrario en la lista de salida).


1
Te estás perdiendo el valor del resultado
Dejell

Tenga en cuenta que ambos están iterando el diccionario y obteniendo valores por su clave, por lo que, en términos de rendimiento, esta no es una solución óptima.
Ron Klein

1
@Dejell: como dice el colaborador, interpreta la pregunta como "¿puedo ordenar la lista de claves según los valores?". No necesitamos los valores en el resultado, los tenemos en el diccionario.
Max

36

Si los valores son numéricos, también puede usarlos Counterde colecciones .

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    

¿qué pasa si su diccionario es >>> x = {'hola': 1, 'python': 5, 'world': 300}
James Sapam

@yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()da [('world', 300), ('python', 5), ('hello', 1)]. Esto realmente funciona para cualquier tipo de valor ordenable (aunque muchas otras operaciones de Contador requieren que los valores sean comparables a los ints).
lvc

34

En Python 2.7, simplemente haga:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

copiar y pegar desde: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Disfruta ;-)


25

Este es el código:

import operator
origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
    print foo

Aquí están los resultados:

Original

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Rango

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}

25

Prueba el siguiente enfoque. Definamos un diccionario llamado mydict con los siguientes datos:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

Si uno quisiera ordenar el diccionario por claves, podría hacer algo como:

for key in sorted(mydict.iterkeys()):
    print "%s: %s" % (key, mydict[key])

Esto debería devolver el siguiente resultado:

alan: 2
bob: 1
carl: 40
danny: 3

Por otro lado, si uno quisiera ordenar un diccionario por valor (como se pregunta en la pregunta), podría hacer lo siguiente:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

El resultado de este comando (ordenar el diccionario por valor) debería devolver lo siguiente:

bob: 1
alan: 2
danny: 3
carl: 40

¡Increíble! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):le permite ordenar por una subclave
Andomar

me da un error de sintaxis cerca de lambda en Python3
Suleman Elahi

21

A partir de Python 3.6, los dictobjetos ahora se ordenan por orden de inserción. Está oficialmente en las especificaciones de Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Antes de eso, tenías que usar OrderedDict.

La documentación de Python 3.7 dice:

Modificado en la versión 3.7: el orden del diccionario está garantizado como orden de inserción. Este comportamiento fue detalle de implementación de CPython desde 3.6.


¡Funciona genial! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))para DESC
vizyourdata

20

Puede crear un "índice invertido", también

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Ahora tu inverso tiene los valores; cada valor tiene una lista de claves aplicables.

for k in sorted(inverse):
    print k, inverse[k]

19

Puedes usar las colecciones . Tenga en cuenta que esto funcionará tanto para valores numéricos como no numéricos.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

77
¿Cómo es esto diferente de la respuesta de Ivan Sas ?
Peter Mortensen el

15

Puede usar un omitir dict que es un diccionario que está ordenado permanentemente por valor.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

Si usa keys(), values()oitems() luego iterará en orden ordenado por valor.

Se implementa utilizando la estructura de datos de la lista de omisión.


¿Podemos cambiar el orden de clasificación? En este momento, se está enviando, pero quiero cancelar.
Suleman Elahi

afaik tendrías que negar tus valores para revertir el orden
malto

wow, no pienso así ... gracias.
Suleman Elahi

14

También puede usar la función personalizada que se puede pasar a la clave.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)

12
from django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict

2
la pregunta era: ordenar por valor, no por teclas ... Me gusta ver una función. Puede importar colecciones y, por supuesto, usar ordenado (data.values ​​())
Remi

10

Como señaló Dilettant , ¡Python 3.6 ahora mantendrá el orden ! Pensé en compartir una función que escribí que facilita la clasificación de un iterable (tupla, lista, dictado). En el último caso, puede ordenar por claves o valores, y puede tener en cuenta la comparación numérica. ¡Solo para> = 3.6!

Cuando intente usar sorted en un iterable que contenga, por ejemplo, cadenas y entradas, sorted () fallará. Por supuesto, puede forzar la comparación de cadenas con str (). Sin embargo, en algunos casos, desea hacer una comparación numérica real donde 12sea ​​menor que 20(que no es el caso en la comparación de cadenas). Entonces se me ocurrió lo siguiente. Cuando desee una comparación numérica explícita, puede usar el indicador num_as_numque intentará realizar una ordenación numérica explícita intentando convertir todos los valores en flotantes. Si eso tiene éxito, hará una ordenación numérica, de lo contrario recurrirá a la comparación de cadenas.

Comentarios para mejoras o solicitudes de inserción son bienvenidos.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    elif isinstance(iterable, tuple):
      sorted_list = tuple(_sort(None))
      return sorted_list
    elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")

9

Aquí hay una solución usando zip on d.values()yd.keys() . Algunas líneas en este enlace (en objetos de vista de Diccionario) es:

Esto permite la creación de pares (valor, clave) usando zip (): pares = zip (d.values ​​(), d.keys ()).

Entonces podemos hacer lo siguiente:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]

9

Por supuesto, recuerde, debe usarlo OrderedDictporque los diccionarios Python normales no mantienen el orden original.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

Si no tiene Python 2.7 o superior, lo mejor que puede hacer es iterar sobre los valores en una función de generador. (Hay un OrderedDictpara 2.4 y 2.6 aquí , pero

a) No sé qué tan bien funciona

y

b) Tienes que descargarlo e instalarlo, por supuesto. Si no tiene acceso administrativo, me temo que la opción está fuera).


def gen(originalDict):
    for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

También puede imprimir cada valor

for bleh, meh in gen(myDict):
    print(bleh, meh)

Recuerde eliminar los paréntesis después de la impresión si no usa Python 3.0 o superior


los diccionarios regulares de Python no mantienen el orden original ; a partir de Python 3.7, lo hacen.
gerrit

7

Use ValueSortedDict de dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

6

Esto funciona en 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)

6

Acabo de aprender habilidades relevantes de Python para todos .

Puede usar una lista temporal para ayudarlo a ordenar el diccionario:

#Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# create a temporary list
tmp = []

# iterate through the dictionary and append each tuple into the temporary list 
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

Si desea ordenar la lista en orden descendente, simplemente cambie la línea de clasificación original a:

tmp = sorted(tmp, reverse=True)

Usando la comprensión de la lista, el único revestimiento sería:

#Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Salida de muestra:

#Asending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]

esto se ordena por claves, no por valores.
Rubel

Si desea imprimirlo en el formato inicial, debe hacer: print ([(k, v) para v, k en orden ([(v, k) para k, v en d.items ()])]). El resultado es: [('naranja', 1.0), ('manzana', 500.1), ('piña', 789.0), ('plátano', 1500.2)]. Con [(k, v) para v, k en orden ([(v, k) para k, v en d.items ()], reverse = True)] la salida es: [('banana', 1500.2), ('piña', 789.0), ('manzana', 500.1), ('naranja', 1.0)]
Hermes Morales

5

Iterar a través de un dict y ordenarlo por sus valores en orden descendente:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(word, dictionary[word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1

5

Si sus valores son enteros y usa Python 2.7 o posterior, puede usarlos en collections.Counterlugar de dict. El most_commonmétodo le dará todos los elementos, ordenados por el valor.


5

En aras de la integridad, estoy publicando una solución usando heapq . Tenga en cuenta que este método funcionará tanto para valores numéricos como no numéricos

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]

4

Debido a los requisitos para mantener la compatibilidad con versiones anteriores de Python , creo que la solución OrderedDict es muy poco inteligente. Desea algo que funcione con Python 2.7 y versiones anteriores.

Pero la solución de colecciones mencionada en otra respuesta es absolutamente excelente, porque se vuelve a capacitar una conexión entre la clave y el valor que, en el caso de los diccionarios, es extremadamente importante.

No estoy de acuerdo con la opción número uno presentada en otra respuesta, porque tira las llaves.

Utilicé la solución mencionada anteriormente (el código se muestra a continuación) y conservé el acceso tanto a las claves como a los valores y, en mi caso, el orden estaba en los valores, pero la importancia era el orden de las claves después de ordenar los valores.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.