Respuestas:
Si OrderedDict()
es así, puede acceder fácilmente a los elementos indexando obteniendo las tuplas de pares (clave, valor) de la siguiente manera
>>> 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 para Python 3.X
dict.items
devolvería un objeto de vista dict iterable en lugar de una lista. Necesitamos ajustar la llamada a una lista para hacer posible la indexación.
>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')
list(d.items())
list(d.items())
utilizando next(islice(d.items(), 1))
para obtener('bar', 'spam')
¿Tiene que usar un OrderedDict o desea específicamente un tipo de mapa que esté ordenado de alguna manera con indexación posicional rápida? Si es lo último, considere uno de los muchos tipos de dict ordenados de Python (que ordena los pares clave-valor en función del orden de clasificación de las claves). Algunas implementaciones también admiten indexación rápida. Por ejemplo, el proyecto sortedcontainers tiene un tipo SortedDict solo para este propósito.
>>> 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
con una función clave para evitar comparaciones. Al igual que: SortedDict(lambda key: 0, ...)
. Las claves estarán sin clasificar pero permanecerán en un orden estable y son indexables.
Aquí hay un caso especial si desea la primera entrada (o cerca de ella) en un OrderedDict, sin crear una lista. (Esto se ha actualizado 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 primera vez que dices "siguiente ()", realmente significa "primero").
En mi prueba informal, next(iter(d.items()))
con un pequeño OrderedDict es solo un poquito más rápido que items()[0]
. Con un OrderedDict de 10,000 entradas, next(iter(d.items()))
fue aproximadamente 200 veces más rápido que items()[0]
.
PERO si guarda la lista de elementos () una vez y luego usa mucho la lista, podría ser más rápido. O si repetidamente {crea un iterador de ítems () y avanza hasta la posición que desea}, eso podría ser más lento.
OrderedDict
s no tienen un iteritems()
método, por lo que tendrá que hacer lo siguiente con el fin de obtener el primer punto: next(iter(d.items()))
.
d.items()
no parece ser un iterador, por lo tanto, ¿por delante no ayudará? Todavía devolverá la lista completa :(
odict_iterator
y me confirmaron en IRC #python que esto no hace una copia de la lista.
Es dramáticamente más eficiente usar IndexedOrderedDict del indexed
paquete.
Siguiendo el comentario de Niklas, hice un punto de referencia en OrderedDict e IndexedOrderedDict con 1000 entradas.
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 es ~ 100 veces más rápido en elementos de indexación en una posición específica en este caso específico.
indexed.py
lugar de indexed
.
Este wiki comunitario intenta recopilar respuestas existentes.
Python 2.7
En Python 2, las keys()
, values()
y items()
las funciones de OrderedDict
las listas de retorno. Usando values
como ejemplo, la forma más simple es
d.values()[0] # "python"
d.values()[1] # "spam"
Para colecciones grandes donde solo le importa un índice único, puede evitar crear la lista completa utilizando las versiones del generador iterkeys
, itervalues
y iteritems
:
import itertools
next(itertools.islice(d.itervalues(), 0, 1)) # "python"
next(itertools.islice(d.itervalues(), 1, 2)) # "spam"
El paquete indexed.py proporciona IndexedOrderedDict
, que está diseñado para este caso de uso y será la opción más rápida.
from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0] # "python"
d.values()[1] # "spam"
El uso de itervalues puede ser considerablemente más rápido para diccionarios grandes con acceso aleatorio:
$ 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 tiene las mismas dos opciones básicas (lista vs generador), pero los métodos dict devuelven generadores por defecto.
Método de la lista:
list(d.values())[0] # "python"
list(d.values())[1] # "spam"
Método generador:
import itertools
next(itertools.islice(d.values(), 0, 1)) # "python"
next(itertools.islice(d.values(), 1, 2)) # "spam"
Los diccionarios de Python 3 son un orden de magnitud más rápido que python 2 y tienen aceleraciones similares para usar generadores.
+--------+-----------+----------------+---------+
| size | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
| 1000 | .0316 | .0165 | .00262 |
| 10000 | .288 | .166 | .00294 |
| 100000 | 3.53 | 1.48 | .00332 |
+--------+-----------+----------------+---------+
Es una nueva era y con los diccionarios Python 3.6.1 ahora conservan su orden. Estas semánticas no son explícitas porque eso requeriría la aprobación de BDFL. Pero Raymond Hettinger es la segunda mejor opción (y más divertida) y argumenta que los diccionarios se ordenarán por mucho tiempo.
Así que ahora es fácil crear secciones de un diccionario:
test_dict = {
'first': 1,
'second': 2,
'third': 3,
'fourth': 4
}
list(test_dict.items())[:2]
Nota: La preservación del orden de inserción dictonario ahora es oficial en Python 3.7 .
para OrderedDict () puede acceder a los elementos indexando obteniendo las tuplas de pares (clave, valor) de la siguiente manera 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
método devuelve un objeto de vista de diccionario interable en lugar de una lista, y no admite la división o indexación. Entonces primero deberías convertirlo en una lista. docs.python.org/3.3/library/stdtypes.html#dict-views