Convertir dict a OrderedDict

138

Estoy teniendo problemas para usar la collections.OrderedDictclase. Estoy usando Python 2.7 en Raspbian, la distribución de Debian para Raspberry Pi. Estoy tratando de imprimir dos diccionarios para poder compararlos (lado a lado) para una aventura de texto. El orden es esencial para comparar con precisión. No importa lo que intente, los diccionarios imprimen en su forma desordenada habitual.

Esto es lo que obtengo cuando lo hago en mi RPi:

import collections

ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship
# OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])

Obviamente, hay algo que no está bien porque está imprimiendo la llamada a la función y colocando las claves y los grupos de valores en una lista anidada ...

Esto es lo que obtuve al ejecutar algo similar en mi PC:

import collections

Joe = {"Age": 28, "Race": "Latino", "Job": "Nurse"}
Bob = {"Age": 25, "Race": "White", "Job": "Mechanic", "Random": "stuff"}

#Just for clarity:
Joe = collections.OrderedDict(Joe)
Bob = collections.OrderedDict(Bob)

print Joe
# OrderedDict([('Age', 28), ('Race', 'Latino'), ('Job', 'Nurse')])
print Bob
# OrderedDict([('Age', 25), ('Race', 'White'), ('Job', 'Mechanic'), ('Random', 'stuff')])

Esta vez, está en orden, pero no debería imprimir las otras cosas, ¿verdad? (Ponerlo en la lista y mostrar la llamada a la función).

¿Dónde estoy cometiendo mi error? No debería tener nada que ver con la versión pi de Python porque es solo la versión de Linux.

pythonpiboy
fuente
3
Nota: OrderedDictse ordena por orden de inserción, no por orden de teclas alfanuméricas.
el.pescado

Respuestas:

214

Primero está creando un diccionario , luego pasa ese diccionario a un OrderedDict. Para las versiones de Python <3.6 (*) , cuando lo haga, el orden ya no será correcto. dictes inherentemente no ordenado

Pase una secuencia de tuplas en su lugar:

ship = [("NAME", "Albatross"),
        ("HP", 50),
        ("BLASTERS", 13),
        ("THRUSTERS", 18),
        ("PRICE", 250)]
ship = collections.OrderedDict(ship)

Lo que ves cuando imprimes OrderedDictes su representación , y es completamente correcto. OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])solo le muestra, en una representación reproducible , cuáles son los contenidos del OrderedDict.


(*) : En la implementación de CPython 3.6, eldict tipo se actualizó para usar una estructura interna más eficiente en memoria que tiene el efecto secundario de preservar el orden de inserción, y por extensión, el código que se muestra en la pregunta funciona sin problemas. A partir de Python 3.7, la especificación del lenguaje Python se ha actualizado para requerir que todas las implementaciones de Python sigan este comportamiento. Vea esta otra respuesta mía para obtener más detalles y también por qué es posible que aún desee usar un OrderedDict()para ciertos casos.

Martijn Pieters
fuente
Ok, entonces OrderedDict CREARÁ el diccionario para mí? Además, para imprimir sin la representación reproducible, ¿puedo imprimir la variable en la que se usa OrderedDict? es decir: print ship ?? Gracias :)
pythonpiboy
3
Pregunta: De la manera que ha descrito, OrderedDict está haciendo una "lista" ordenada. ¿Eso no vence el propósito? Está creando solo una lista de elementos, no diccionarios con claves y valores ...
pythonpiboy
9
El tipo actúa como ambos; Un mapeo que retiene el orden. Para crear uno con pedidos, debe darle elementos en orden . Dado que un dict estándar (en cualquier otra cosa que no sea PyPI o Python 3.6+) no puede hacer eso, en su lugar, le da una lista de tuplas. Una vez que OrderedDictse crea , es un diccionario.
Martijn Pieters
44
Parece que la confusión es de asumir que un OrderedDict "aplica" un pedido, en lugar de simplemente retener un pedido. Ciertamente supuse que ordenaría la entrada en la creación, o que la función items () devolvería los elementos ordenados independientemente de cuándo se insertaron. En cambio, solo mantiene cualquier orden que proporciones.
whiterook6
2
@ whiterook6: no es un diccionario ordenado no. Es un diccionario ordenado, un diccionario que registra el orden de los pares clave-valor y le permite reordenar esos pares. Compare esto con las listas, que son secuencias ordenadas .
Martijn Pieters
36

Si no puede editar esta parte del código donde se definió su dict, puede solicitarlo en cualquier momento de la forma que desee, de esta manera:

from collections import OrderedDict

order_of_keys = ["key1", "key2", "key3", "key4", "key5"]
list_of_tuples = [(key, your_dict[key]) for key in order_of_keys]
your_dict = OrderedDict(list_of_tuples)
Jan Rozycki
fuente
11

La mayoría de las veces vamos a OrderedDict cuando requerimos un pedido personalizado, no uno genérico como ASC, etc.

Aquí está la solución propuesta:

import collections
ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship


new_dict = collections.OrderedDict()
new_dict["NAME"]=ship["NAME"]
new_dict["HP"]=ship["HP"]
new_dict["BLASTERS"]=ship["BLASTERS"]
new_dict["THRUSTERS"]=ship["THRUSTERS"]
new_dict["PRICE"]=ship["PRICE"]


print new_dict

Esto se generará:

OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])
OrderedDict([('NAME', 'Albatross'), ('HP', 50), ('BLASTERS', 13), ('THRUSTERS', 18), ('PRICE', 250)])

Nota : Los nuevos diccionarios ordenados mantienen su orden cuando se eliminan las entradas. Pero cuando se agregan nuevas claves, las claves se agregan hasta el final y el orden no se mantiene ( documento oficial )

Abdul Majeed
fuente
2

Use dict.items (); puede ser tan simple como lo siguiente:

ship = collections.OrderedDict(ship.items())
Mohammad Ali
fuente