Pregunta ¿Cómo ordeno un diccionario por valor?


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, así que esa 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 sobre el desbordamiento de la pila ¿Cómo ordeno una lista de diccionarios por valores del diccionario en Python? 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.


2932
2018-03-05 00:49


origen


Respuestas:


No es posible ordenar un diccionario, solo para obtener una representación de un diccionario que está ordenado. Los diccionarios son intrínsecamente sin orden, pero otros tipos, como listas y tuplas, no lo son. Por lo tanto, necesita un tipo de datos ordenados para representar los valores ordenados, que serán 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_x será una lista de tuplas ordenadas por el segundo elemento en cada tupla. dict(sorted_x) == x.

Y para aquellos que deseen clasificar 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 ya que no se permite desempaquetar [1] nosotros podemos usar

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

3550
2018-03-05 00:59



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

Bueno, en realidad es posible hacer un "orden por valores de diccionario". Recientemente tuve que hacer eso en un Code Golf (Pregunta de desbordamiento de pila) Code golf: tabla de frecuencia de palabras) Abreviado, el problema era del 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, se simplifica aquí como:

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

a continuación, puede obtener una lista de las palabras, ordenadas por frecuencia de uso con sorted(d, key=d.get) - el género itera sobre las teclas del diccionario, usando el número de ocurrencias de palabras como una 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 puedo ordenar por valor?", Y creo que el OP intentaba abordar ese problema. Y la solución es hacer una especie de lista de claves, basada en los valores, como se muestra arriba.


967
2017-07-05 08:01



Podrías usar:

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

Esto ordenará el diccionario por los valores de cada entrada dentro del diccionario, desde el más pequeño hasta el más grande.


601
2018-02-13 16:33



Los dicts no se pueden ordenar, pero puedes construir 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))

165
2018-03-05 01:05



En el reciente Python 2.7, tenemos el nuevo OrderedDict tipo, 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 crear un nuevo diccionario ordenado a partir 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)])

128
2017-07-05 02:50



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

Aunque encontré útil la respuesta aceptada, también me sorprendió que no se haya actualizado para hacer referencia OrderedDict de la biblioteca estándar colecciones módulo como una alternativa viable, 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)])

El oficial OrderedDict La documentación también ofrece un ejemplo muy similar, pero usando un lambda para la función de ordenamiento:

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

75
2017-12-05 09:46



A menudo puede ser muy útil para 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}

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

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

ordenando con el puntaje más alto 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 similar a Python:

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

64
2017-08-30 00:30



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


    ordenado ([(valor, clave) para (clave, valor) en mydict.items ()])

O optimizado un poco como lo sugiere John Fouhy;


    ordenado ((valor, clave) para (clave, valor) en mydict.items ())


57
2018-03-05 01:06



A partir de Python 3.6 el dict incorporado será ordenado

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

Si dice las dos expresiones resultantes de la tabla de columnas 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 salida más tarde como:

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

ceder 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:

Tal como lo propuso Raymond Hettinger en 2012 (ver correo sobre python-dev con el tema "Diccionarios más compactos con iteración más rápida") y ahora (en 2016) anunció en un correo electrónico de Victor Stinner a python-dev con el tema "Python 3.6 dict se vuelve compacto y obtiene una versión privada, y las palabras clave se ordenan" debido a la corrección / implementación del número 27350 "Dict compacto y ordenado" en Python 3.6 ahora podremos utilizar una función incorporada para mantener el orden de inserción.

Esperemos que esto conduzca a una implementación de capa delgada OrderedDict 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 lo inspeccionará cuidadosamente, si esto supera la prueba del tiempo, y cuáles serán los siguientes pasos.

Es hora de repensar nuestros hábitos de codificación para no perder las posibilidades que ofrece el orden estable de:

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

El primero 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 dicts como almacenamiento intermedio en el procesamiento de las tuberías.

Raymond Hettinger amablemente proporcionó documentación que explica "Los diccionarios Tech Behind 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 decoradas con 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 vea la actualización a continuación 2017-12-15):

Como @ajcr señala con razón: "El aspecto de preservación de orden de esta nueva implementación se considera un detalle de implementación y no se debe confiar en él". (desde el whatsnew36) no nit picking, pero la cita fue un poco pesimista ;-). Continúa como "(esto puede cambiar en el futuro, pero es deseable tener esta nueva implementación de dict en el lenguaje para unas pocas versiones antes de cambiar la especificación del lenguaje para ordenar la semántica preservadora de orden para todas las implementaciones actuales y futuras de Python; ayuda a preservar la compatibilidad con versiones anteriores del lenguaje donde el orden de iteración aleatorio todavía está en vigencia, por ejemplo, Python 3.5). "

Entonces, como en algunos idiomas humanos (por ejemplo, el alemán), el uso da forma al idioma y el testamento 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 el orden de inserción" es la decisión. ¡Gracias!

Por lo tanto, el efecto secundario CPython de la versión 3.6 del pedido de inserción de Dict ahora se está convirtiendo en parte de la especificación de idioma (y ya no solo en un detalle de implementación). Ese hilo de correo también surgió algunos objetivos de diseño distintivos para collections.OrderedDict como lo recordó Raymond Hettinger durante la discusión.


48
2017-09-10 10:05



Diccionario dado

e = {1:39, 4:34, 7:110, 2:87}

Clasificación

sred = sorted(e.items(), key=lambda value: value[1])

Resultado

[(4, 34), (1, 39), (2, 87), (7, 110)]

Puede usar una función lambda para ordenar cosas por valor y almacenarlas procesadas dentro de una variable, en este caso sred con mi el diccionario original.

¡Espero que ayude!


41
2018-01-25 14:54



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 según los valores?" Significa claramente que quiere una lista de las claves clasificadas de acuerdo con 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).


36
2017-11-18 14:19