In Python, come posso scorrere un dizionario in ordine di chiavi ordinato?


211

Esiste una funzione esistente che termina di seguito, dove si dtrova un dizionario:

return d.iteritems()

che restituisce un iteratore non ordinato per un determinato dizionario. Vorrei restituire un iteratore che passa attraverso gli elementi ordinati per chiave . Come lo faccio?

Risposte:


171

Non l'ho testato molto ampiamente, ma funziona in Python 2.5.2.

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

Se sei abituato a fare for key, value in d.iteritems(): ...invece degli iteratori, funzionerà comunque con la soluzione sopra

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

Con Python 3.x, utilizzare d.items()invece di d.iteritems()restituire un iteratore.


29
usa .items()invece di iteritems(): come diceva @Claudiu, iteritems non funziona per Python 3.x, ma items()è disponibile da Python 2.6.
Remi,

40
Questo non è ovvio. In effetti, items()crea un elenco e quindi utilizza la memoria, mentre iteritems()essenzialmente non utilizza la memoria. Cosa usare dipende principalmente dalle dimensioni del dizionario. Inoltre, lo strumento di conversione automatica da Python 2 a Python 3 ( 2to3) si occupa automaticamente della conversione da iteritems()a items(), quindi non è necessario preoccuparsene.
Eric O Lebigot,

5
@HowerHell usa a collections.OrderedDictquindi ordina una volta e ottieni sempre gli oggetti in ordine.
Mark Harviston,

9
Ma @EOL, anche se iteritems()non usa la memoria, tutto deve essere archiviato nella memoria sorted(), quindi non c'è differenza tra l'uso di items()e iteritems()qui la memoria.
Richard,

8
@Richard: Anche se è vero che tutti gli elementi devono essere estratti in memoria, vengono memorizzati due volte con items()(nell'elenco restituito da items()e nell'elenco ordinato) e solo una volta con iteritems()(solo nell'elenco ordinato).
Eric O Lebigot,

83

Usa la sorted()funzione:

return sorted(dict.iteritems())

Se si desidera un iteratore effettivo sui risultati ordinati, poiché sorted()restituisce un elenco, utilizzare:

return iter(sorted(dict.iteritems()))

Ciò non riesce per me: <type 'exceptions.TypeError'>: iter () ha restituito un non-iteratore di tipo 'list'
mike

Questo probabilmente perché usi "dict" come nome della variabile. "dict" è in realtà il nome tipo dei dizionari. Basta usare un altro nome come "mydict" qui e voilà.
utku_karatas,

1
Continua a non funzionare. Sei in ordine positivo () restituisce un altro iteratore, anziché un elenco normale?
mike,

quando e dove si verifica questa eccezione? puoi

1
D'accordo, luppolo. Non penso di aver mai chiamato .next () direttamente tranne quando saltavo le linee nei file. La nostra soluzione iter (ordinata (dict.iteritems ())) finisce per fare una copia dell'intero dict in memoria nella fase "ordinata (", quindi il vantaggio

39

Le chiavi di un dict sono archiviate in una tabella hash in modo che sia il loro "ordine naturale", cioè psuedo-casuale. Qualsiasi altro ordinamento è un concetto del consumatore del dict.

sort () restituisce sempre un elenco, non un dict. Se lo passi a dict.items () (che produce un elenco di tuple), restituirà un elenco di tuple [(k1, v1), (k2, v2), ...] che possono essere utilizzate in un ciclo in un modo molto simile a un dict, ma non è comunque un dict !

foo = {
    'a':    1,
    'b':    2,
    'c':    3,
    }

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

Quanto segue sembra un dict in un ciclo, ma non lo è, è un elenco di tuple che vengono decompresse in k, v:

for k,v in sorted(foo.items()):
    print k, v

Praticamente equivalente a:

for k in sorted(foo.keys()):
    print k, foo[k]

Ok, ma non voglio un Dict o un Elenco, voglio un Iteratore. Come posso costringerlo a diventare Iteratore?
mike,

2
sorted(foo.keys())è meglio come equivalente sorted(foo), poiché i dizionari restituiscono le loro chiavi quando ripetono (con il vantaggio di non essere costretti a creare l' foo.keys()elenco intermedio, forse - a seconda di come sorted()è implementato per gli iterabili).
Eric O Lebigot,

Mi chiedo quale sia la migliore per la velocità e / o la memoria k in sorted(foo.keys()):che tira i tasti o for k,v in sorted(foo.items()):che restituisce una copia delle coppie dell'elenco del dizionario, immaginosorted(foo.keys())
CrandellWS,

1
@CrandellWS: il modo migliore per rispondere alla domanda temporale è con il modulo timeit Python .
Peter Rowell,

1
@frank - Risposta breve: No. Un dict è un array con la chiave effettiva che è un hash del valore della chiave fornita. Anche se alcune implementazioni possono essere abbastanza prevedibili e alcune possono persino stipulare questo contratto, non conto di nulla quando si tratta di ordinare l'hash. Vedi questo post per ulteriori informazioni sul comportamento 3.6+. In particolare nota la prima risposta.
Peter Rowell,

31

La risposta di Greg è giusta. Nota che in Python 3.0 dovrai farlo

sorted(dict.items())

come iteritemssarà andato.


Ciò non riesce per me: <type 'exceptions.TypeError'>: iter () ha restituito un non iteratore di tipo 'list'
mike

3
"Non usare le macchine perché in futuro avremo degli hoverboard"
JJ,

7

Ora puoi usare anche OrderedDictin Python 2.7:

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

Qui hai la pagina delle novità per la versione 2.7 e l' API OrderedDict .


Ciò restituirà la chiave, i valori nell'ordine in cui sono inseriti, non in un ordine ordinato (cioè alfabetico).
Tony Suffolk, 66

5

In generale, si può ordinare un dict in questo modo:

for k in sorted(d):
    print k, d[k]

Per il caso specifico nella domanda, avendo un "drop in sostituzione" per d.iteritems (), aggiungi una funzione come:

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

e così la linea di fine cambia da

return dict.iteritems()

per

return sortdict(dict)

o

return sortdict(dict, reverse = True)

5
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

Questo metodo ha ancora un ordinamento O (N log N), tuttavia, dopo una breve heapify lineare, restituisce gli oggetti in ordine ordinato, rendendolo teoricamente più efficiente quando non è sempre necessario l'intero elenco.


4

Se vuoi ordinare in base all'ordine in cui gli elementi sono stati inseriti anziché l'ordine delle chiavi, dovresti dare un'occhiata alle collezioni di Python.OrderedDict . (Solo Python 3)


3

ordinati restituisce un elenco, quindi l'errore quando si tenta di scorrere su di esso, ma poiché non è possibile ordinare un dict, è necessario gestire un elenco.

Non ho idea di quale sia il contesto più ampio del tuo codice, ma potresti provare ad aggiungere un iteratore all'elenco risultante. così forse ?:

return iter(sorted(dict.iteritems()))

ovviamente ora tornerai alle tuple perché ordinate ha trasformato il tuo dict in un elenco di tuple

es: dire che il tuo dict era: {'a':1,'c':3,'b':2} ordinato lo trasforma in un elenco:

[('a',1),('b',2),('c',3)]

quindi quando si esegue l'iterazione effettiva dell'elenco si ritorna (in questo esempio) una tupla composta da una stringa e un numero intero, ma almeno si sarà in grado di scorrere su di essa.


2

Supponendo che tu stia utilizzando CPython 2.x e abbia un dizionario di grandi dimensioni mydict, l'utilizzo di sort (mydict) sarà lento perché ordinato crea un elenco ordinato delle chiavi di mydict.

In tal caso, potresti voler esaminare il mio pacchetto ordereddict che include un'implementazione C di sorteddict in C. Specialmente se devi esaminare più volte l'elenco ordinato di chiavi in ​​diverse fasi (es. Numero di elementi) della vita dei dizionari.

http://anthon.home.xs4all.nl/Python/ordereddict/

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.