python una ¿Cómo ordeno un diccionario por valor?




recorrer diccionario python (24)

Tengo un diccionario de valores leído 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 clasificar según los valores?

Nota: He leído la pregunta de desbordamiento de 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.


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

Y para aquellos que deseen ordenar en 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 el desempaquetado [1] , podemos usar

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

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

Bueno, en realidad es posible hacer una "clasificación por valores de diccionario". Recientemente tuve que hacer eso en un código de golf (pregunta de desbordamiento de pila Código de golf: tabla de frecuencia de palabras ) Resuelto, el problema fue 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 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

luego puede obtener una lista de las palabras, ordenadas por frecuencia de uso con sorted(d, key=d.get) : la ordenación se repite sobre las claves 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 a lo que la gente suele referirse con "puedo ordenar fácilmente un diccionario por clave, pero cómo lo hago por valor", y creo que el OP estaba tratando de resolver ese problema. Y la solución es hacer una especie de lista de las claves, según los valores, como se muestra arriba.


Si sus valores son enteros, y usa Python 2.7 o más reciente, puede usar collections.Counter . dict lugar de dict . El método most_common le dará todos los elementos, ordenados por el valor.


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, se podría hacer algo como:

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

Esto debería devolver la siguiente salida:

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) debe devolver lo siguiente:

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

Técnicamente, los diccionarios no son secuencias, y por lo tanto no pueden ser ordenados. Puedes hacer algo como

sorted(a_dictionary.values())

Asumir que el rendimiento no es un gran problema.


También puede utilizar 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)

Una forma más de hacerlo es usar la función labmda.

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

Por supuesto, recuerde que debe usar OrderedDict porque los diccionarios regulares de Python no conservan 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 OrderedDict para 2.4 y 2.6 here , pero

a) I don't know about how well it works 

y

b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
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 utiliza Python 3.0 o superior


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

Puede usar un dictado de omisión, que es un diccionario 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 las keys() , los values() o los items() , iterará en orden ordenado por valor.

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


Casi lo mismo que la respuesta de Hank Gay;

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

O optimizado un poco según lo sugerido por John Fouhy;

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


Puedes usar las collections.Counter . collections.Counter . 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)])

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

Si bien la respuesta aceptada me pareció útil, 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 ofrece un ejemplo muy similar, pero utilizando un 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)])

Esto devuelve la lista de pares clave-valor en el diccionario, ordenados por valor de mayor a menor:

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

Para el diccionario ordenado por clave, use lo siguiente:

sorted(d.items(), reverse=True)

El retorno es una lista de tuplas porque los diccionarios en sí no se pueden ordenar.

Esto se puede imprimir o enviar a cómputo adicional.


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]

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

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

Comentarios para mejorar o empujar solicitudes de bienvenida.

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")

Utilice ValueSortedDict de los 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)]

Si los valores son numéricos, también puede usar Contador de 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)]    

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

Una lista ordenada de los valores de dict:

sorted(d.values())

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

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

En Python 2.7, simplemente haz:

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


Tuve el mismo problema, y ​​lo resolví así:

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

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

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


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 ids de cadenas únicas como claves y valores numéricos como valores en un dictado de Python v3.6 + incorporado, ahora debe respetar el orden de inserción.

Si dice las dos expresiones de tabla de columna 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 dictado de Python 3.6+ incorporado):

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 (consulte el correo en python-dev con el tema "Más diccionarios compactos con una iteración más rápida" ) y ahora (en 2016) se anunció en un correo de Victor Stinner a python-dev con el tema "Python 3.6 dict se convierte en compacta y obtiene una versión privada; y las palabras clave se ordenan " debido a la corrección / implementación del problema 27350 " Compacto y orden dictado " en Python 3.6, ahora podremos usar un dictado 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 @ JimFasarakis-Hilliard indicó, 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á el paso 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 el ordenamiento estable de:

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

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 de dict s como almacenamiento intermedio en tuberías de procesamiento.

Raymond Hettinger proporcionó amablemente la documentación que explica " The Tech Behind Python 3.6 Dictionaries " - de su presentación del Grupo Meetup de San Francisco Python 2016-DEC-08.

Y tal vez algunas páginas de preguntas y respuestas con mucha decoración de Overflow de Stack 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 ver a continuación la actualización 2017-12-15):

Como @ajcr señala acertadamente: "El aspecto de preservar el orden de esta nueva implementación se considera un detalle de la implementación y no se debe confiar en él". (del Whatsnew36 ) no de picking de liendres, 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 de idioma para obligar a la semántica de preservación de órdenes para todas las implementaciones actuales y futuras de Python; esto también ayuda a preservar la compatibilidad con versiones anteriores del lenguaje en el que el orden de iteración aleatorio sigue vigente, por ejemplo, Python 3.5) ".

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

Actualización 2017-12-15:

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

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

Por lo tanto, el efecto secundario de la versión 3.6 CPython 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 surgió algunos objetivos de diseño distintivos para las collections.OrderedDict OrderedDict según lo recordó Raymond Hettinger durante la discusión.


Puedes usar la función ordenada de Python

sorted(iterable[, cmp[, key[, reverse]]])

Por lo tanto puedes usar:

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

Visite este enlace para obtener más información sobre la función ordenada: https://docs.python.org/2/library/functions.html#sorted


Iterar a través de un dict y ordenarlos 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

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 las cosas por valor y almacenarlas procesadas dentro de una variable, en este caso sred con el diccionario original.

¡Espero que ayude!





dictionary