¿Cómo puedo ordenar un diccionario por clave?

941

¿Cuál sería una buena manera de ir de {2:3, 1:89, 4:5, 3:0}a {1:89, 2:3, 3:0, 4:5}?
Revisé algunas publicaciones pero todas usan el operador "ordenado" que devuelve tuplas.

Antonio
fuente
39
Los diccionarios están intrínsecamente sin clasificar. Mostrar el diccionario es otra cuestión. De todos modos, ¿para qué necesitas realmente clasificarlo?
Karl Knechtel el
15
Los diccionarios no están ordenados. ellos simplemente no están. si desea revisar los elementos en orden, tendría que hacer algo como dijo usando ordenado como "for key in sorted (d.keys ())" suponiendo que d es el nombre de su diccionario
Ryan Haining
3
@KarlKnechtel: mi caso de uso es que tengo una aplicación CLI que tiene un menú primitivo y las opciones de menú están en un diccionario como las teclas. Me gustaría mostrar las teclas alfabéticamente para la cordura del usuario.
Randy
44
Tenga en cuenta que los dictados ahora están ordenados por orden de inserción (python 3.6+). Algunas respuestas a continuación señalan esto.
matiasg

Respuestas:

941

Los diccionarios estándar de Python no están ordenados. Incluso si clasificara los pares (clave, valor), no podría almacenarlos dictde una manera que preservara el orden.

La forma más fácil es usar OrderedDict, que recuerda el orden en que se han insertado los elementos:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

No importa cómo odse imprima el camino; funcionará como se esperaba:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

Para los usuarios de Python 3, uno debe usar el en .items()lugar de .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
fuente
1
Usé esto y funciona, supongo que es más código y redundancia, pero hace el trabajo, # dict desordenado d = {2: 3, 1:89, 4: 5, 3: 0} orderDict = {} para la clave ordenada (d.iterkeys ()) :pedidoDict [clave] = d [clave]
Antony
44
@achrysochoou: si eso funcionó, debe haber sido por pura suerte. Como le han dicho, los diccionarios regulares no tienen un concepto de clasificación, sin importar si asigna las claves ordenadas o de manera aleatoria.
Ricardo Cárdenes el
21
Para python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
Python 3.7+ no debería necesitar orderDict ya que ahora ordena por defecto :-)
Aneuway
3
Del manual de Python 3.7.4: "La ejecución de la lista (d) en un diccionario devuelve una lista de todas las teclas utilizadas en el diccionario, en orden de inserción". Por lo tanto, el orden de inserción es algo que se conserva y en el que podemos confiar.
Mostafa Hadian
415

Los diccionarios en sí no tienen elementos ordenados como tales, si desea imprimirlos, etc. en algún orden, aquí hay algunos ejemplos:

En Python 2.4 y superior:

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

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

da:

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

(Python debajo de 2.4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Fuente: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

James
fuente
2
También puede usar OrderedDict en python 2.4+ como en la respuesta de NPE
radtek
1
y si está usando elementos () puede hacerlo comofor key, value in sorted(mydict.items())"
beep_check
Los diccionarios en sí mismos no tienen elementos pedidos como tales -> ya no es cierto!
minexew
¿Cómo es que puedes explicar?
James
204

De la collectionsdocumentación de la biblioteca de Python :

>>> from collections import OrderedDict

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

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> 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)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Dennis
fuente
44
¡increíble! Chicos, si quieren invertir el orden (ascendente a descendente) simplemente agreguen, reverse=Truepor ejemploOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia
1
En PyCharm, no importa qué diccionario use, siempre recibo esta advertencia:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Para CPython / PyPy 3.6, y cualquier Python 3.7 o superior, esto se hace fácilmente con:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
fuente
3
Otra forma de escribir lo mismo es usar una comprensión: {key:d[key] for key in sorted(d.keys())}
flow2k el
42

Hay varios módulos de Python que proporcionan implementaciones de diccionario que mantienen automáticamente las claves en orden ordenado. Considere el módulo sortedcontainers que es implementaciones de Python puro y rápido como C. También hay una comparación de rendimiento con otras opciones populares comparadas entre sí.

El uso de un dict ordenado es una solución inadecuada si necesita agregar y eliminar constantemente pares clave / valor mientras itera.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

El tipo SortedDict también admite búsquedas de ubicación indexadas y eliminación, lo que no es posible con el tipo dict incorporado.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])
GrantJ
fuente
32

Simplemente:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Salida:

1 89
2 3
3 0
4 5
usuario3769249
fuente
66
sdes una lista de tuplas, no un diccionario. (aunque útil.)
nischi
24

Como otros han mencionado, los diccionarios son inherentemente desordenados. Sin embargo, si el problema es simplemente mostrar los diccionarios de forma ordenada, puede anular el __str__método en una subclase de diccionario y utilizar esta clase de diccionario en lugar de la incorporada dict. P.ej.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Tenga en cuenta que esto no cambia nada sobre cómo se almacenan las claves, el orden en que volverán cuando las repita, etc., solo cómo se muestran con printo en la consola de Python.

Brian
fuente
19

Encontrado otra forma:

import json
print json.dumps(d, sort_keys = True)

upd:
1. esto también clasifica los objetos anidados (gracias @DanielF).
2. los diccionarios de python no están ordenados, por lo tanto, esto es adecuado para imprimir o asignar solo a str.

tschesseket
fuente
Pero esto también ordena las claves de los objetos anidados, que podrían no ser deseados.
Daniel F
Tenga en cuenta que esto solo clasifica los diccionarios, no las listas, por ejemplo, dict.keys () no se ordenarán porque es una lista.
Andrew
16

En Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

da

1 89
2 3
3 0
4 5
Evgeny Tryastsin
fuente
13

El diccionario de Python no estaba ordenado antes de Python 3.6. En la implementación CPython de Python 3.6, el diccionario mantiene el orden de inserción. Desde Python 3.7, esto se convertirá en una característica del lenguaje.

En el registro de cambios de Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

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 (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 ordenar 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).

En el documento de Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

La ejecución de la lista (d) en un diccionario devuelve una lista de todas las claves utilizadas en el diccionario, en orden de inserción (si desea ordenarlas , simplemente use ordenadas (d) en su lugar).

Entonces, a diferencia de las versiones anteriores, puede ordenar un dict después de Python 3.6 / 3.7. Si desea ordenar un dict anidado incluyendo el sub-dict dentro, puede hacer:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb

Guangyang Li
fuente
11

Aquí encontré una solución más simple para ordenar el dict de Python por clave usando pprint. p.ej.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

pero mientras usa pprint devolverá dict ordenado

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}
Atul Arvind
fuente
10

Hay una manera fácil de ordenar un diccionario.

De acuerdo a su pregunta,

La solucion es :

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Donde c, es el nombre de su diccionario).

Este programa da el siguiente resultado:

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

como quisieras

Otro ejemplo es:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Da la salida:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Da la salida:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Da la salida:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Por lo tanto, al cambiarlo por claves, valores y elementos, puede imprimir como deseaba. ¡Espero que esto ayude!

Sree
fuente
8

Generará exactamente lo que quieres:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

Pero esta no es la forma correcta de hacer esto, porque podría mostrar un comportamiento distinto con diferentes diccionarios, lo que he aprendido recientemente. Por lo tanto, Tim sugirió la manera perfecta en la respuesta de mi consulta que estoy compartiendo aquí.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
jax
fuente
¿Qué significa "mostrar un comportamiento distinto con diferentes diccionarios"? ¿Cuál es el "comportamiento distinto" que ordenado no puede manejar?
ingyhere
6

Creo que lo más fácil es ordenar el dict por clave y guardar la clave ordenada: par de valores en un nuevo dict.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Para hacerlo más claro:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value
lallolu
fuente
6

Puede crear un nuevo diccionario clasificando el diccionario actual por clave según su pregunta.

Este es tu diccionario

d = {2:3, 1:89, 4:5, 3:0}

Cree un nuevo diccionario d1 ordenando este d usando la función lambda

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 debe ser {1: 89, 2: 3, 3: 0, 4: 5}, ordenados según las claves en d.

Amit Prafulla
fuente
5

Los dictados de Python no están ordenados. Por lo general, esto no es un problema ya que el caso de uso más común es hacer una búsqueda.

La forma más sencilla de hacer lo que desea sería crear una collections.OrderedDictinserción de los elementos en orden ordenado.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Si necesita iterar, como han sugerido los anteriores, la forma más sencilla sería iterar sobre las teclas ordenadas. Ejemplos

Imprimir valores ordenados por claves:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Obtenga una lista de valores ordenados por claves:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
fuente
2
for k,value in sorted(d.items()):es mejor: evita acceder al dict por clave nuevamente en el bucle
Jean-François Fabre
4

Se me ocurre una sola línea de clasificación de dict.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

Esperamos que esto sea útil.

Jeevan Chaitanya
fuente
4

Esta función clasificará cualquier diccionario de forma recursiva por su clave. Es decir, si cualquier valor en el diccionario también es un diccionario, también se ordenará por su clave. Si está ejecutando en CPython 3.6 o superior, se puede hacer un cambio simple para usar un en dictlugar de un OrderedDict.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)
Boo Boo
fuente
2

Chicos, ustedes están complicando las cosas ... es muy simple

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

El resultado es:

{'A':2,'B':1,'C':3}
Derick Fdo
fuente
Voté porque no sabía que pprint ordena los diccionarios para mostrarlos, pero el OP realmente ha preguntado acerca de "pasar" de una orden sin clasificar a una ordenada, es decir, OP parece querer algo que permanece ordenado en la memoria, tal vez para algún algoritmo que requiere claves ordenadas
Capitán Lepton
Este método no permitirá la asignación encadenada ya que pprint no devuelve ninguno. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (última llamada más reciente): Archivo "<stdin>", línea 1, en <module> AttributeError: el objeto 'NoneType' no tiene atributo 'type'
2

La solución más simple es que debe obtener una lista de la clave dict ordenada y luego iterar sobre dict. Por ejemplo

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

A continuación se mostrará la salida (orden de finalización)

e 30
b 13
d 4
c 2
a 1
Shafiq
fuente
2

Una manera fácil de hacer esto:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 
pr94
fuente
1

Una comparación temporal de los dos métodos en 2.7 muestra que son prácticamente idénticos:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 
Jesuisme
fuente
1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)
Mohammad Mahjoub
fuente
1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}
Mahdi Ghelichi
fuente
0

Mi sugerencia es esta, ya que le permite ordenar un dict o mantener un dict ordenado a medida que agrega elementos y podría necesitar agregar elementos en el futuro:

Construye una dictdesde cero a medida que avanzas. Tenga una segunda estructura de datos, una lista, con su lista de claves. El paquete bisect tiene una función de inserción que permite insertar en una lista ordenada u ordenar su lista después de completar completamente su dict. Ahora, cuando itera sobre su dict, en su lugar itera sobre la lista para acceder a cada clave de manera ordenada sin preocuparse por la representación de la estructura de dict (que no fue hecha para ordenar).

demongolem
fuente
0

Para la forma en que se formula la pregunta, la mayoría de las respuestas aquí son contestarla correctamente.

Sin embargo, considerando cómo se deben hacer realmente las cosas , teniendo en cuenta décadas y décadas de informática, me sorprende totalmente que en realidad solo haya una respuesta aquí (de GrantJ usuario de ) que sugiera el uso de contenedores asociativos ordenados (contenedores ordenados) que ordena los elementos según la clave en su punto de inserción.

Eso evitará un impacto masivo en el rendimiento por cada llamada de sort(...)(como mínimo O(N*log(N)), donde Nhay una cantidad de elementos (lógicamente, esto se aplica a todas las soluciones aquí que sugieren usar el sort(...)). Tenga en cuenta que para todas esas soluciones, sort(...)será necesario se llamará cada vez que se deba acceder a la colección ordenada DESPUÉS de que se modificó agregando / eliminando elementos ...

PeterB
fuente
-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)
usuario7070507
fuente
3
Hay otras 14 respuestas. ¿Puede explicar un poco su código y por qué podría ser mejor que las otras soluciones?
FelixSFD
Votación negativa: código bastante ilegible con nombres de variables cortos sin significado l, l2, l3. Parece ser un intento de un algoritmo indirecto e ineficiente sin conocimiento de las funciones estándar de Python, y en cualquier caso no funciona cuando se prueba en un pequeño ejemplo en la publicación original.
Capitán Lepton