¿Cómo clasifico un diccionario por valor?

3417

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 es la clave del diccionario.

Puedo ordenar las claves, pero ¿cómo puedo ordenar en función de los valores?

Nota: He leído la pregunta de Stack Overflow aquí. ¿Cómo puedo ordenar una lista de diccionarios por un valor del diccionario? y probablemente podría cambiar mi código para tener una lista de diccionarios, pero como 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.

5
  • 9
    La estructura de datos del diccionario no tiene un orden inherente. Puede iterar a través de él, 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 otra estructura de datos para la representación. Daishiman 5 de julio de 2010 a las 2:08
  • 135
    "sorted ()" puede operar en diccionarios (y devuelve una lista de claves ordenadas), así que creo que es consciente 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, probablemente lo que desee sea un dict. bobpaul 15 feb 2013 a las 19:04
  • Las tres salidas (claves, valores, ambos) para ordenar diccionarios se tratan aquí en un estilo claro y conciso: stackoverflow.com/questions/16772071/sort-dict-by-value-pythonJStrahl 7 de marzo de 2016 a las 10:14
  • 2
    @Daishiman Es posible que la clase base no esté ordenada, pero OrderedDict sí, por supuesto. Taylor Edmiston 9 de septiembre de 2017 a las 1:10
  • 1
    En Python 3.6+, los diccionarios conservan el orden de inserción. Por supuesto, esto 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 31 dic 2018 a las 13:30
5890
+500

Python 3.7+ o CPython 3.6

Los dicts conservan el orden de inserción en Python 3.7+. Lo mismo en CPython 3.6, pero es un detalle de implementación .

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

o

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

Python más antiguo

No es posible ordenar un diccionario, solo para 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 ordenados para representar 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_xserá una lista de tuplas ordenadas por el segundo elemento en cada tupla. dict(sorted_x) == x.

Y para aquellos que deseen ordenar por claves en lugar de 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, dado que no se permite desempaquetar , 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 dictado, puede usar collections.OrderedDict:

import collections

sorted_dict = collections.OrderedDict(sorted_x)
8
  • 46
    para tiempos en varios diccionarios ordenados por esquemas de valor: writeonly.wordpress.com/2008/08/30/…Gregg Lind 14 de marzo de 2009 a las 17:55
  • 181
    sorted_x.reverse()le dará un orden descendente (por el segundo elemento de tupla)saidimu apale 3 de mayo de 2010 a las 5:24
  • 456
    saidimu: Como ya estamos usando sorted(), es mucho más eficiente pasar el reverse=Trueargumento. rmh 5 de julio de 2010 a las 2:59
  • 125
    En python3 he usado un lambda: sorted(d.items(), key=lambda x: x[1]). ¿Funcionará esto en Python 2.x? Keyo 15 feb 2011 a las 15:05
  • 86
    OrderedDict agregado a las colecciones en 2.7. Ejemplo de clasificación que se muestra en: docs.python.org/library/…monkut 24/04/11 a las 6:31
1443

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

Bueno, en realidad es posible "ordenar por valores de diccionario". Recientemente tuve que hacer eso en un Code Golf (Stack Overflow question Code golf: Word Frequency Chart ). Resumido, el problema era del tipo: dado un texto, cuente la frecuencia con la que 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 ocurrencias de cada palabra como valor, simplificado aquí como:

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

luego puede obtener una lista de las palabras, ordenadas por frecuencia de uso con sorted(d, key=d.get)- la clasificación itera sobre las claves del diccionario, utilizando el número de apariciones de palabras como clave de clasificació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 suele decir con "Puedo ordenar fácilmente un diccionario por clave, pero ¿cómo lo ordeno 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.

3
  • 35
    Esto también es bueno, pero key=operator.itemgetter(1)debería ser más escalable para la eficiencia quekey=d.getsmci 9/12/11 a las 21:18
  • 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 crean una función cuando se llama, no la usa directamente como en su ejemplo. Y una iteración simple en un dictado usa las claves sin los valoresIzkata 19/08/2014 a las 20:21
  • 23
    Vengo del futuro para contaros collections.Counter, que tiene un most_commonmétodo que puede interesarte :)Eevee 25 de junio de 2017 a las 20:47
991

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, simplemente agregue reverse=True:

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

Aporte:

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

Producción:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
6
  • 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: PUsAndRufus 20/0213 a las 10:38
  • 62
    Preferiría key=lambda (k, v): vpersonalmenteClaudiu 9/04/2015 a las 23:08
  • @Keyo ¿no debería ser que devuelva una lista ordenada de claves (ordenadas por valores), no (k,v)tuplas? Eso es lo que obtengo con Python 2.7.10. @Nyxynyx agregue el parámetro reverse = True para ordenar en orden descendente. dhj 16/11/15 a las 16:49
  • 42
    @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 5 feb 16 a las 17:53
  • 5
    dict(sorted(d.items(), key=lambda x: x[1])). Dr_Hope 16/07/19 a las 15:39
252

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))
2
  • ¿En qué orden están colocadas las llaves 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 18/06/12 a las 10:04
  • 4
    Los dictados ahora se pueden ordenar, comenzando con CPython 3.6 y todas las demás implementaciones de Python comenzando con 3.7Boris 24 abr.20 a las 19:38
173

En Python 2.7 reciente, tenemos el nuevo tipo OrderedDict , que recuerda el orden en el 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 crear un nuevo diccionario ordenado a partir del original, ordenando por valores:

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

El OrderedDict se comporta como un dictado 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)])
7
  • 5
    No se trata de esto, no se trata de mantener el orden de las claves, sino de "ordenar por valor"Nas Banov 5 de julio de 2010 a las 7:07
  • 10
    @Nas Banov: NO está ordenando por clave. está ordenando en el orden, creamos los elementos. en nuestro caso, ordenamos por valor. Desafortunadamente, el dict de 3 elementos fue elegido, por lo que el orden fue el mismo, cuando se clasificaron por valor y clave, así que amplié el dict de muestra. mykhal 5 de julio de 2010 a las 10:56
  • sorted(d.items(), key=lambda x: x[1])¿Puede explicar qué xsignifica, por qué puede llevar x[1]a lambda? ¿Por qué no puede ser x[0]? ¡Muchos gracias! JZAU 8 de noviembre de 2013 a las 5:12
  • 1
    @Boern d.items()devuelve un contenedor de (key, value)tuplas similar a una lista . [0]accede al primer elemento de la tupla - la clave - y [1]accede al segundo elemento - el valor. BallpointBen 10/04/18 a las 14:29
  • 2
    Nota: A partir de 3.6 (como un detalle de implementación de CPython / PyPy) y a partir de 3.7 (como garantía del lenguaje Python), el formato plano también dictestá ordenado por inserción, por lo que puede reemplazarlo OrderedDictcon el dictcódigo que se ejecuta en Python moderno. 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 que sean sensibles al orden. Utiliza mucha más memoria que simple dict, así que si puedes, dictes el camino a seguir. ShadowRanger 4 de septiembre de 2019 a las 13:09
112

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 del módulo de colecciones de bibliotecas 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 usando 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)])
103

Casi 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())
3
  • 10
    ... y al igual que con la respuesta de Hank Gay, no necesita los corchetes. sorted () felizmente tomará cualquier iterable, como una expresión generadora. John Fouhy 5 de marzo de 2009 a las 1:45
  • Es posible que aún deba intercambiar los elementos de la 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 3 de mayo de 2010 a las 5:22
  • no, es mejor dejar los corchetes, porque sortedtendrá que reconstruir la lista de todos modos, y la reconstrucción desde gencomp será más rápida. Bueno para el codegolf, malo para la velocidad. Conserva la ([])versión fea . Jean-François Fabre 7 dic 2017 a las 21:21
81

A menudo puede resultar muy útil utilizar namedtuple . Por ejemplo, tiene un diccionario de 'nombre' como claves y 'puntuación' como valores y desea ordenar por 'puntuación':

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

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

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

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

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 Pythonically así:

player = best[1]
player.name
    'Richard'
player.score
    7
2
  • ¿Cómo podría volver a convertirlo en un diccionario? rowana 7 feb 2017 a las 20:31
  • as_list = [Player (v, k) for (k, v) in d.items ()] as_dict = dict ((p.name, p.score) for p in as_list)Remi 23 feb 2017 a las 12:31
80

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

Buenas noticias, por lo que el caso de uso original del OP de mapeo de pares recuperados de una base de datos con identificadores de cadena únicos como claves y valores numéricos como valores en un dictado de Python v3.6 + incorporado, ahora debería 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 por supuesto), entonces:

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

Permitir que se genere más tarde como:

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

ceder en este caso (¡para el nuevo diccionario 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:

Como lo propuso en 2012 Raymond Hettinger (cf. mail en python-dev con el 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 el asunto "El dictado de Python 3.6 se convierte compact y obtiene una versión privada, y las palabras clave se ordenan " debido a la correcció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.

Con suerte, esto conducirá 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 que abre el ordenamiento estable de:

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

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

El segundo, ya que fomenta el uso más fácil de los dicts como almacenamiento intermedio en las tuberías de procesamiento.

Raymond Hettinger brindó amablemente documentación que explica " La tecnología detrás de los diccionarios de Python 3.6 ", de su presentación de San Francisco Python Meetup Group 2016-DEC-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 también requerirán una actualización por versión.

Caveat Emptor (pero también consulte la siguiente actualización 2017-12-15):

Como @ajcr señala con razón: "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". (de whatsnew36 ) no es una pizca de liendre, pero la cita fue un poco pesimista ;-). Continúa como "(esto puede cambiar en el futuro, pero se desea tener esta nueva implementación de dict en el lenguaje para algunas versiones antes de cambiar la especificación del lenguaje 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 aleatorio todavía está vigente, por ejemplo, Python 3.5) ".

Entonces, como en algunos lenguajes humanos (por ejemplo, alemán), el uso da forma al lenguaje, y la voluntad ahora ha sido declarada ... en whatsnew36 .

Actualización 2017-12-15:

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

Make it so. "Dict keeps insertion order" is the ruling. Thanks!

Por lo tanto, el efecto secundario de CPython de la versión 3.6 del orden de inserción de 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 mostró algunos objetivos de diseño distintivos, collections.OrderedDictcomo lo recordó Raymond Hettinger durante la discusión.

6
  • dieciséis
    Se debe enfatizar la advertencia en la página 'whatsnew' a la que 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 asumir 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 usando OrderedDictpara garantizar el pedido. Alex Riley 10 de septiembre de 2016 a las 20:15
  • @ajcr gracias por la advertencia, muy apreciado - ya que los emoticonos y los quizás fueron entretejidos en mi respuesta, estos deberían indicar, el cambio es masivo pero, por supuesto, solo está disponible para CPython (implementación de referencia) y PyPy. Para algo completamente diferente ... Rara vez hablo de detalles de no implementación al codificar instrucciones hombre-máquina. Si solo hubiera sido Jython ;-) ... Puede que no hubiera tenido el coraje de escribirlo. Dilettant 10 de septiembre de 2016 a las 20:22
  • OrderedDictdefinitivamente no se dejará caer; en su lugar, se convertirá en una envoltura delgada alrededor de la implementación de dict actual (por lo que podría agregar que también se volverá más compacto). Agregar ese fragmento con el ImportErrorno es la mejor idea debido a que engaña a los lectores OrderedDicty no sirve de nada. Dimitris Fasarakis Hilliard 10/12/2016 a las 13:33
  • @ 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 10/12/2016 a las 13:58
  • 8
    @AlexRiley Esta advertencia ya no es precisa. Python3.7 garantiza diccionarios ordenados. gerrit 19/12/18 a las 17:12
47

Tuve el mismo problema y lo resolví así:

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

(Las personas que respondieron "No es posible ordenar un dictado" no leyeron la pregunta. De hecho, "Puedo ordenar por las claves, pero ¿cómo puedo ordenar en función de los valores?" Significa claramente 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).

3
  • 1
    Falta el valor del resultadoDejell 7 de ene. De 2014 a las 20:54
  • Tenga en cuenta que está iterando el diccionario y obteniendo valores por su clave, por lo que en cuanto al rendimiento, esta no es una solución óptima. Ron Klein 21 de septiembre de 2016 a las 8:00
  • 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 12 de enero de 2019 a las 3:19
45

Si los valores son numéricos, también puede utilizar 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)]    
2
  • ¿qué pasa si su diccionario es >>> x = {'hola': 1, 'python': 5, 'mundo': 300}James 28/12/13 a las 13:17
  • @yopy Counter({'hello':1, 'python':5, 'world':300}).most_common()da [('world', 300), ('python', 5), ('hello', 1)]. En realidad, esto funciona para cualquier tipo de valor ordenable (aunque muchas otras operaciones de Contador requieren que los valores sean comparables a los ints). lvc 28 de diciembre de 2013 a las 13:58
38

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

Disfrutar ;-)

29

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}
28

Pruebe 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
2
  • ¡Impresionante! for key, value in sorted(mydict.iteritems(), key=lambda (k,v): v["score"]):le permite ordenar por una subclaveAndomar 7 de julio de 2017 a las 19:08
  • esto no funciona en versiones posteriores de Python que no admiten el desempaquetado de tuplas y donde los dictados ya no tienen iteritems ()lb_so 5 de junio a las 10:30
26

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:

Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was implementation detail of CPython from 3.6.

1
  • ¡Funciona genial! dict(sorted(words.items(), key=lambda x: x[1], reverse=True))para DESCvizyourdata 19/11/18 a las 20:10
24

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]
22

Puede utilizar las colecciones . Tenga en cuenta que esto funcionará tanto para valores numéricos como para valores 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)])
1
17

También puede usar una 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)
1
  • Esta es la única respuesta que funcionó hasta ahora en Python 2.7rkochev 19 de enero a las 12:44
16

Puede usar un skip 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()o items(), iterará en orden ordenado por valor.

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

2
  • ¿Podemos cambiar el orden de clasificación? Ahora mismo, se está enviando, pero yo quiero rechazarlo. Suleman Elahi 6 feb.20 a las 12:15
  • afaik, tendría que negar sus valores para revertir el ordenmalthe 6 feb.20 a las 13:14
14
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
1
  • 2
    La pregunta era: ordenar por valor, no por claves ... Me gusta ver una función. Puede importar colecciones y, por supuesto, usar sorted (data.values ​​())Remi 30/08/11 a las 0:38
13

Por supuesto, recuerde, debe usarlo OrderedDictporque los diccionarios de 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 generadora. (Hay un OrderedDict2,4 y un 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á descartada).


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 todos los valores

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

Recuerde eliminar los paréntesis después de imprimir si no usa Python 3.0 o superior

1
  • Los diccionarios de Python normales no mantienen el orden original ; a partir de Python 3.7, sí lo hacen. gerrit 19/12/18 a las 17:13
12

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, dict). 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 e ints, 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 12es 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 la bandera num_as_numque intentará hacer una clasificación numérica explícita tratando de convertir todos los valores en flotantes. Si tiene éxito, hará una clasificación numérica; de lo contrario, recurrirá a la comparación de cadenas.

Comentarios para mejorar 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")
11

Aquí hay una solución que usa zip en d.values()yd.keys() . Algunas líneas más abajo de este enlace (en los objetos de la vista Diccionario) es:

This allows the creation of (value, key) pairs using zip(): pairs = 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

Utilice ValueSortedDict de los dictados :

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)]
9

Acabo de aprender una habilidad relevante de Python para todos .

Puede utilizar una lista temporal para ayudarle 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)

Utilizando la comprensión de listas, la única línea 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')]
3
  • esto es ordenar por claves, no por valores. Rubel 4 feb.20 a las 13:50
  • Si desea imprimirlo en el formato inicial, debe hacer: print ([(k, v) para v, k en sorted ([(v, k) para k, v en d.items ()])]). La salida es: [('naranja', 1.0), ('manzana', 500.1), ('piña', 789.0), ('banana', 1500.2)]. Con [(k, v) para v, k en ordenados ([(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 4 de mayo de 2020 a las 20:14
  • @Rubel ¡Comprueba la salida! por ejemplo, [(1.0, 'naranja'), (500.1, 'manzana'), (789.0, 'piña'), (1500.2, 'plátano')] se ordena según los valores. mcgag 7 de agosto a las 3:34
8

Repita un dict y ordénelo 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
7

Si sus valores son números enteros y usa Python 2.7 o más reciente, puede usar en collections.Counterlugar de dict. El most_commonmétodo le dará todos los elementos, ordenados por valor.

7

Esto funciona en 3.1.x:

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

En aras de la integridad, estoy publicando una solución usando heapq . Tenga en cuenta que este método funcionará para valores numéricos y 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)]
5
months = {"January": 31, "February": 28, "March": 31, "April": 30, "May": 31,
          "June": 30, "July": 31, "August": 31, "September": 30, "October": 31,
          "November": 30, "December": 31}

def mykey(t):
    """ Customize your sorting logic using this function.  The parameter to
    this function is a tuple.  Comment/uncomment the return statements to test
    different logics.
    """
    return t[1]              # sort by number of days in the month
    #return t[1], t[0]       # sort by number of days, then by month name
    #return len(t[0])        # sort by length of month name
    #return t[0][-1]         # sort by last character of month name


# Since a dictionary can't be sorted by value, what you can do is to convert
# it into a list of tuples with tuple length 2.
# You can then do custom sorts by passing your own function to sorted().
months_as_list = sorted(months.items(), key=mykey, reverse=False)

for month in months_as_list:
    print month