Come mantenere chiavi / valori nello stesso ordine dichiarato?


320

Ho un dizionario che ho dichiarato in un ordine particolare e voglio mantenerlo sempre in quell'ordine. Le chiavi / i valori non possono davvero essere tenuti in ordine in base al loro valore, lo voglio solo nell'ordine in cui l'ho dichiarato.

Quindi se ho il dizionario:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

Non è in questo ordine se lo visualizzo o lo provo, esiste un modo per assicurarsi che Python manterrà l'ordine esplicito in cui ho dichiarato le chiavi / i valori?

Risposte:


229

Da Python 3.6 in poi, il dicttipo standard mantiene l'ordine di inserimento predefinito.

Definizione

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

si tradurrà in un dizionario con le chiavi nell'ordine elencato nel codice sorgente.

Ciò è stato ottenuto utilizzando un array semplice con numeri interi per la tabella hash sparse, in cui tali numeri interi si indicizzano in un altro array che memorizza le coppie chiave-valore (più l'hash calcolato). Quest'ultimo array si limita a memorizzare gli elementi in ordine di inserimento e l'intera combinazione utilizza effettivamente meno memoria dell'implementazione utilizzata in Python 3.5 e precedenti. Vedi l' idea originale post di Raymond Hettinger per i dettagli.

In 3.6 questo era ancora considerato un dettaglio di implementazione; vedere l' Novità in Python 3.6 documentazione :

L'aspetto che preserva l'ordine di questa nuova implementazione è considerato un dettaglio dell'implementazione e non dovrebbe essere invocato (questo potrebbe cambiare in futuro, ma si desidera avere questa nuova implementazione di dict nella lingua per alcune versioni prima di cambiare le specifiche della lingua imporre la semantica che preserva l'ordine per tutte le implementazioni attuali e future di Python; ciò aiuta anche a preservare la retrocompatibilità con le versioni precedenti del linguaggio in cui l'ordine di iterazione casuale è ancora in vigore, ad esempio Python 3.5).

Python 3.7 eleva questi dettagli di implementazione a una specifica del linguaggio , quindi è ora obbligatorio che dictmantenga l'ordine in tutte le implementazioni di Python compatibili con quella versione o più recente. Vedi la dichiarazione del BDFL .

In alcuni casi potresti comunque voler utilizzare la collections.OrderedDict()classe , poiché offre alcune funzionalità aggiuntive oltre al dicttipo standard . Come essere reversibile (questo si estende agli oggetti vista ) e supportare il riordino (tramite il move_to_end()metodo ).


Purtroppo questo non è rilevante per la creazione di dizionari . I dizionari specificati come quello nell'esempio nel codice non sono garantiti per mantenere lo stesso ordine. Ciò significa che è necessario creare un dict vuoto e inserire manualmente ogni elemento se si desidera controllare l'ordine.
nulla101

8
@ naught101: no, questo non si applica alla creazione dict. In Python 3.7 e versioni successive, l'utilizzo di un display dict, come mostrato nella domanda, è garantito per elencare questi tasti in ordine . Le coppie chiave-valore scritte vengono inserite da sinistra a destra, poiché le specifiche della lingua garantiscono che : Se viene fornita una sequenza di coppie chiave / riferimento separate da virgola, vengono valutate da sinistra a destra per definire le voci del dizionario . La dict()documentazione include anche un esempio.
Martijn Pieters

175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

contiene

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

Se i valori sono True(o qualsiasi altro oggetto immutabile), puoi anche utilizzare:

OrderedDict.fromkeys(words, True)

2
Vale la pena notare, ovviamente, che la parte 'immutabile' non è una regola dura e veloce che Python applicherà - è "solo" una buona idea.
PVC

11
essere consapevoli del fatto che soluzioni come: OrderedDict(FUTURE=[], TODAY=[], PAST=[])non funzioneranno, quando menzionate approcci: OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])manterranno l'ordine.
andilabs

2
@andi Ho avuto un altro problema, quando si utilizza jsonify, OrderedDict sembra perso il suo ordine quando si generano i dati json. In ogni caso per risolvere questo?
tyan

github.com/pallets/flask/issues/974 questo può essere usato per risolvere il problema ..
tyan

5
Python3.7 ora ha dict ordinato per impostazione predefinita. mail.python.org/pipermail/python-dev/2017-December/151283.html
sertsedat

167

Piuttosto che spiegare la parte teorica, darò un semplice esempio.

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

16
C'è un modo per assegnare in serie OrderedDict come il tipo Dict?
tyan

2
OrderedDictrisolve davvero il problema, ma ... in questo particolare esempio ottieni esattamente lo stesso risultato usando un dizionario standard
Tonechas

2
@Tonechas: ho appena provato l'esempio con un dizionario standard e ho ottenuto {'aol': 1, 'foo': 3}Quindi penso che sia un buon esempio illustrativo.
twasbrillig,

4
C'è una lezione per tutti: è stato scoperto (penso alla versione 2.4) che l' hash prevedibile di Python potrebbe causare vulnerabilità di sicurezza , quindi ora non c'è garanzia che anche due diverse esecuzioni dello stesso codice forniranno lo stesso ordine in uno standard dict.
holdenweb,

1
@tyan è possibile chiamare OrderedDict.update()con una iterabili contenenti coppie chiave-valore: d1.upate([(key1, val1), (key2, val2)]).
Ruud Althuizen,

37

Nota che questa risposta si applica alle versioni di Python precedenti a Python3.7. CPython 3.6 mantiene l'ordine di inserimento nella maggior parte dei casi come dettaglio di implementazione. A partire da Python3.7 in poi, è stato dichiarato che le implementazioni DEVONO mantenere l'ordine di inserimento conforme.


i dizionari Python non sono ordinati. Se vuoi un dizionario ordinato, prova collezioni.OrderedDict .

Nota che OrderedDict è stato introdotto nella libreria standard in Python 2.7. Se hai una versione precedente di Python, puoi trovare le ricette per i dizionari ordinati su ActiveState .


vedi il post di @ martijn sopra. Da Python 3.6 in poi, dict supporta l'ordinamento di inserzione.
tpk,

13

I dizionari utilizzeranno un ordine che rende la ricerca efficiente e non puoi cambiarlo,

Potresti semplicemente usare un elenco di oggetti (una tupla a 2 elementi in un caso semplice, o persino una classe) e aggiungere elementi alla fine. È quindi possibile utilizzare la ricerca lineare per trovare elementi al suo interno.

In alternativa, è possibile creare o utilizzare una diversa struttura di dati creata con l'intenzione di mantenere l'ordine.


I dizionari useranno un ordine che rende efficiente la ricerca. Infine, qualcuno lo ha sottolineato.
Scharette,

7

Mi sono imbattuto in questo post mentre cercavo di capire come far funzionare OrderedDict. PyDev per Eclipse non è riuscito a trovare OrderedDict, quindi ho deciso di creare una tupla dei valori chiave del mio dizionario come vorrei che fossero ordinati. Quando avevo bisogno di visualizzare il mio elenco, ho semplicemente ripetuto i valori della tupla e ho inserito la 'chiave' ripetuta dalla tupla nel dizionario per recuperare i miei valori nell'ordine in cui ne avevo bisogno.

esempio:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

È un po 'ingombrante, ma ho poco tempo ed è la soluzione alternativa che mi è venuta in mente.

nota: l'elenco delle liste si avvicina a quello che qualcun altro ha suggerito non ha davvero senso per me, perché le liste sono ordinate e indicizzate (e sono anche una struttura diversa rispetto ai dizionari).


Ottima soluzione Lo userò per scrivere json su file, sempre nello stesso ordine.
Hrvoje T,

6

Non puoi davvero fare quello che vuoi con un dizionario. Hai già d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}creato il dizionario . Ho scoperto che non c'era modo di mantenerlo in ordine una volta che è già stato creato. Quello che ho fatto è stato invece creare un file JSON con l'oggetto:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

Ero solito:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

quindi utilizzato:

print json.dumps(r)

verificare.


1
Quindi perché non iniziare con un OrderedDict da un elenco? Il file JSON non aggiunge nulla qui.
Martijn Pieters

Sì, l'elenco è più utile per mantenere l'ordine, ma la risposta era riguardo alla domanda sull'ordinamento dei dizionari. Informare semplicemente le persone sui limiti dell'uso di un dizionario e fornire loro una possibile soluzione se per qualche motivo devono usare un dizionario.
nealous3

1
Ma quella parte è già coperta da risposte molto più antiche, risalenti al 2012.
Martijn Pieters

3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

problema principale che non è più un dict, è un elenco di tuple
Oleg

2

Un'altra alternativa è quella di utilizzare Panda dataframein quanto garantisce l'ordine e la posizione dell'indice degli articoli in una struttura simile a un dict.


1

In generale, è possibile progettare una classe che si comporta come un dizionario, principalmente l'attuazione dei metodi __contains__, __getitem__, __delitem__, __setitem__e un po 'di più. Quella classe può avere qualsiasi comportamento che ti piace, ad esempio suddividere un iteratore ordinato sulle chiavi ...


1

se desideri avere un dizionario in un ordine specifico, puoi anche creare un elenco di elenchi, in cui il primo elemento sarà la chiave e il secondo elemento sarà il valore e sarà simile a questo esempio

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

7
Questo non è un "dizionario" perché non è possibile cercare gli elementi in base alla loro chiave senza cercare nell'intera raccolta (impiegando O (n) tempo).
BHSPitMonkey

1
Sì, non è un dizionario, ma, a seconda della situazione, potrebbe fornire una soluzione valida al problema del poster originale.
SunSparc,

non ha detto esattamente come volevamo, solo che vogliamo essere in grado di ordinarli =), come sempre ci sono molti modi per fare una cosa.
Pelos,

1

Ho avuto un problema simile durante lo sviluppo di un progetto Django. Non ho potuto usare OrderedDict, perché stavo eseguendo una vecchia versione di Python, quindi la soluzione era quella di utilizzare la classe SortedDict di Django:

https://code.djangoproject.com/wiki/SortedDict

per esempio,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

Nota: questa risposta è originaria del 2011. Se hai accesso a Python versione 2.7 o successiva, dovresti avere accesso all'ormai standard collections.OrderedDict, di cui molti esempi sono stati forniti da altri in questo thread.


0

Puoi fare la stessa cosa che ho fatto per il dizionario.

Crea un elenco e svuota il dizionario:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_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.