Conversione di dict in OrderedDict


138

Sto riscontrando problemi nell'uso della collections.OrderedDictclasse. Sto usando Python 2.7 su Raspbian, la distro Debian per Raspberry Pi. Sto cercando di stampare due dizionari per il confronto (fianco a fianco) per un'avventura testuale. L'ordine è essenziale per un confronto accurato. Indipendentemente da ciò che provo, i dizionari stampano nel loro solito modo non ordinato.

Ecco cosa ottengo quando lo faccio sul mio 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)])

Ovviamente c'è qualcosa che non va perché stampa la chiamata di funzione e mette le chiavi e i gruppi di valori in un elenco nidificato ...

Questo è quello che ho ottenuto eseguendo qualcosa di simile sul mio 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')])

Questa volta è in ordine, ma non dovrebbe stampare le altre cose però giusto? (L'inserisce nell'elenco e mostra la chiamata di funzione.)

Dove sto facendo il mio errore? Non dovrebbe avere nulla a che fare con la versione pi di Python perché è solo la versione Linux.


3
Nota: OrderedDictè ordinato per ordine di inserzione, non per ordine di chiave alfanumerica.
el.pescado,

Risposte:


214

Prima devi creare un dizionario , quindi passare quel dizionario a un OrderedDict. Per le versioni Python <3.6 (*) , quando lo fai, l'ordinamento non sarà più corretto.dictnon è intrinsecamente ordinato.

Passa invece in una sequenza di tuple:

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

Quello che vedi quando stampi OrderedDictè la sua rappresentazione ed è del tutto corretto. OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])ti mostra semplicemente, in una rappresentazione riproducibile , quali sono i contenuti di OrderedDict.


(*) : Nell'implementazione di CPython 3.6, il dicttipo è stato aggiornato per utilizzare una struttura interna più efficiente in termini di memoria che ha il felice effetto collaterale di preservare l'ordine di inserimento e, per estensione, il codice mostrato nella domanda funziona senza problemi. A partire da Python 3.7, le specifiche del linguaggio Python sono state aggiornate per richiedere che tutte le implementazioni di Python debbano seguire questo comportamento. Vedi questa altra mia risposta per i dettagli e anche perché potresti voler utilizzare un OrderedDict()per alcuni casi.


Ok, quindi OrderedDict creerà il dizionario per me? Inoltre, per stampare senza la rappresentazione riproducibile, posso semplicemente stampare la variabile in cui viene utilizzato OrderedDict? cioè: print ship ?? Grazie :)
pythonpiboy il

3
Domanda: Nel modo che hai descritto, OrderedDict sta creando un "elenco" ordinato. Questo non sconfigge lo scopo? Sta creando solo un elenco di elementi, non dizionari con chiavi e valori ...
pythonpiboy

9
Il tipo si comporta come entrambi; una mappatura che mantiene l'ordine. Per crearne uno con l'ordinamento, devi dargli gli articoli in ordine . Dato che un dict standard (su qualsiasi cosa diversa da PyPI o Python 3.6+) non può farlo, gli dai invece un elenco di tuple. Una volta che la OrderedDictsi ha creato esso è un dizionario.
Martijn Pieters

4
Sembra che la confusione provenga dall'ipotesi che un OrderedDict "applichi" un ordinamento, piuttosto che conservare solo un ordinamento. Ho certamente pensato che avrebbe ordinato l'input al momento della creazione - o che la funzione items () avrebbe restituito gli oggetti ordinati indipendentemente da quando erano stati inseriti. Invece mantiene solo qualsiasi ordine tu fornisca.
whiterook6,

2
@ whiterook6: non è un dizionario ordinato no. È un dizionario ordinato, un dizionario che registra l'ordine delle coppie chiave-valore e ti consente di riordinare quelle coppie. Confronta questo con gli elenchi, che sono sequenze ordinate .
Martijn Pieters

36

Se non riesci a modificare questa parte di codice in cui è stato definito il tuo dict, puoi comunque ordinarlo in qualsiasi momento e in qualsiasi modo, in questo modo:

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)

11

Il più delle volte andiamo per OrderedDict quando abbiamo richiesto un ordine personalizzato non uno generico come ASC ecc.

Ecco la soluzione proposta:

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

Questo sarà prodotto:

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

Nota : i nuovi dizionari ordinati mantengono il loro ordinamento quando le voci vengono eliminate. Ma quando vengono aggiunte nuove chiavi, le chiavi vengono aggiunte alla fine e l'ordinamento non viene mantenuto ( documento ufficiale )


2

Usa dict.items (); può essere semplice come il seguente:

ship = collections.OrderedDict(ship.items())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.