Risposte:
Se è un OrderedDict()
, puoi accedere facilmente agli elementi indicizzando ottenendo le tuple di coppie (chiave, valore) come segue
>>> import collections
>>> d = collections.OrderedDict()
>>> d['foo'] = 'python'
>>> d['bar'] = 'spam'
>>> d.items()
[('foo', 'python'), ('bar', 'spam')]
>>> d.items()[0]
('foo', 'python')
>>> d.items()[1]
('bar', 'spam')
Nota per Python 3.X
dict.items
restituirebbe un oggetto iterabile vista dict piuttosto che un elenco. Dobbiamo includere la chiamata in un elenco per rendere possibile l'indicizzazione
>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')
list(d.items())
list(d.items())
utilizzando next(islice(d.items(), 1))
per ottenere('bar', 'spam')
Devi usare un OrderedDict o vuoi specificamente un tipo simile a una mappa che sia ordinato in qualche modo con una rapida indicizzazione della posizione? Se quest'ultimo, considera uno dei molti tipi di dict ordinati di Python (che ordina le coppie chiave-valore in base all'ordinamento delle chiavi). Alcune implementazioni supportano anche l'indicizzazione rapida. Ad esempio, il progetto sortcontainers ha un tipo SortedDict proprio per questo scopo.
>>> from sortedcontainers import SortedDict
>>> sd = SortedDict()
>>> sd['foo'] = 'python'
>>> sd['bar'] = 'spam'
>>> print sd.iloc[0] # Note that 'bar' comes before 'foo' in sort order.
'bar'
>>> # If you want the value, then simple do a key lookup:
>>> print sd[sd.iloc[1]]
'python'
SortedDict
una funzione chiave per evitare confronti. Come: SortedDict(lambda key: 0, ...)
. Le chiavi non saranno quindi ordinate ma rimarranno in un ordine stabile e sono indicizzabili.
Ecco un caso speciale se si desidera la prima voce (o vicino ad essa) in un OrderedDict, senza creare un elenco. (Questo è stato aggiornato a Python 3):
>>> from collections import OrderedDict
>>>
>>> d = OrderedDict()
>>> d["foo"] = "one"
>>> d["bar"] = "two"
>>> d["baz"] = "three"
>>> next(iter(d.items()))
('foo', 'one')
>>> next(iter(d.values()))
'one'
(La prima volta che dici "next ()", significa davvero "first".)
Nel mio test informale, next(iter(d.items()))
con un piccolo OrderedDict è solo un po 'più veloce di items()[0]
. Con un OrderedDict di 10.000 voci, next(iter(d.items()))
era circa 200 volte più veloce di items()[0]
.
MA se salvi una volta l'elenco degli oggetti () e poi usi molto l'elenco, questo potrebbe essere più veloce. Oppure se {crei ripetutamente un iteratore items () e lo passi nella posizione desiderata}, ciò potrebbe essere più lento.
OrderedDict
s non hanno un iteritems()
metodo, quindi è necessario effettuare le seguenti operazioni al fine di ottenere il primo elemento: next(iter(d.items()))
.
d.items()
non sembra essere un iteratore, quindi iter davanti non sarà d'aiuto? Restituirà comunque l'elenco completo :(
odict_iterator
e mi è stato confermato su IRC #python che questo non crea una copia dell'elenco.
È notevolmente più efficiente utilizzare IndexedOrderedDict dalindexed
pacchetto.
Dopo il commento di Niklas, ho fatto un benchmark su OrderedDict e IndexedOrderedDict con 1000 voci.
In [1]: from numpy import *
In [2]: from indexed import IndexedOrderedDict
In [3]: id=IndexedOrderedDict(zip(arange(1000),random.random(1000)))
In [4]: timeit id.keys()[56]
1000000 loops, best of 3: 969 ns per loop
In [8]: from collections import OrderedDict
In [9]: od=OrderedDict(zip(arange(1000),random.random(1000)))
In [10]: timeit od.keys()[56]
10000 loops, best of 3: 104 µs per loop
IndexedOrderedDict è ~ 100 volte più veloce nell'indicizzazione di elementi in una posizione specifica in questo caso specifico.
indexed.py
invece di indexed
.
Questa wiki della comunità tenta di raccogliere risposte esistenti.
Python 2.7
In Python 2, i keys()
, values()
e le items()
funzioni delle OrderedDict
liste di ritorno. Usando values
come esempio, il modo più semplice è
d.values()[0] # "python"
d.values()[1] # "spam"
Per le grandi collezioni di cui si preoccupano solo di un unico indice, si può evitare di creare l'elenco completo utilizzando le versioni del generatore, iterkeys
, itervalues
e iteritems
:
import itertools
next(itertools.islice(d.itervalues(), 0, 1)) # "python"
next(itertools.islice(d.itervalues(), 1, 2)) # "spam"
Il pacchetto indexed.py fornisce IndexedOrderedDict
, che è progettato per questo caso d'uso e sarà l'opzione più veloce.
from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0] # "python"
d.values()[1] # "spam"
L'uso di itervalues può essere notevolmente più veloce per dizionari di grandi dimensioni con accesso casuale:
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 1000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i:i+1]'
1000 loops, best of 3: 259 usec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 10000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i:i+1]'
100 loops, best of 3: 2.3 msec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 100000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i:i+1]'
10 loops, best of 3: 24.5 msec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 1000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
10000 loops, best of 3: 118 usec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 10000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
1000 loops, best of 3: 1.26 msec per loop
$ python2 -m timeit -s 'from collections import OrderedDict; from random import randint; size = 100000; d = OrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); next(itertools.islice(d.itervalues(), i, i+1))'
100 loops, best of 3: 10.9 msec per loop
$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 1000; d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.19 usec per loop
$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 10000; d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.24 usec per loop
$ python2 -m timeit -s 'from indexed import IndexedOrderedDict; from random import randint; size = 100000; d = IndexedOrderedDict({i:i for i in range(size)})' 'i = randint(0, size-1); d.values()[i]'
100000 loops, best of 3: 2.61 usec per loop
+--------+-----------+----------------+---------+
| size | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
| 1000 | .259 | .118 | .00219 |
| 10000 | 2.3 | 1.26 | .00224 |
| 100000 | 24.5 | 10.9 | .00261 |
+--------+-----------+----------------+---------+
Python 3.6
Python 3 ha le stesse due opzioni di base (elenco vs generatore), ma i metodi dict restituiscono generatori per impostazione predefinita.
Metodo elenco:
list(d.values())[0] # "python"
list(d.values())[1] # "spam"
Metodo del generatore:
import itertools
next(itertools.islice(d.values(), 0, 1)) # "python"
next(itertools.islice(d.values(), 1, 2)) # "spam"
I dizionari Python 3 sono un ordine di grandezza più veloce di Python 2 e hanno velocità simili per l'uso dei generatori.
+--------+-----------+----------------+---------+
| size | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
| 1000 | .0316 | .0165 | .00262 |
| 10000 | .288 | .166 | .00294 |
| 100000 | 3.53 | 1.48 | .00332 |
+--------+-----------+----------------+---------+
È una nuova era e con i dizionari Python 3.6.1 ora mantengono il loro ordine. Queste semantiche non sono esplicite perché ciò richiederebbe l'approvazione BDFL. Ma Raymond Hettinger è la prossima cosa migliore (e più divertente) e lui fa un caso piuttosto forte che dizionari verrà ordinato per un tempo molto lungo.
Quindi ora è facile creare sezioni di un dizionario:
test_dict = {
'first': 1,
'second': 2,
'third': 3,
'fourth': 4
}
list(test_dict.items())[:2]
Nota: la conservazione dell'ordine di inserimento Dictonary è ora ufficiale in Python 3.7 .
per OrderedDict () puoi accedere agli elementi indicizzando ottenendo le tuple delle coppie (chiave, valore) come segue o usando '.values ()'
>>> import collections
>>> d = collections.OrderedDict()
>>> d['foo'] = 'python'
>>> d['bar'] = 'spam'
>>> d.items()
[('foo', 'python'), ('bar', 'spam')]
>>>d.values()
odict_values(['python','spam'])
>>>list(d.values())
['python','spam']
items
metodo restituisce un oggetto visualizzabile del dizionario anziché un elenco e non supporta lo slicing o l'indicizzazione. Quindi dovresti prima trasformarlo in un elenco. docs.python.org/3.3/library/stdtypes.html#dict-views