Respostas:
Se for um, OrderedDict()
você pode acessar facilmente os elementos indexando, obtendo as tuplas de pares (chave, valor) da seguinte maneira
>>> 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
retornaria um objeto de exibição de ditado iterável em vez de uma lista. Precisamos agrupar a chamada em uma lista para possibilitar a indexação
>>> items = list(d.items())
>>> items
[('foo', 'python'), ('bar', 'spam')]
>>> items[0]
('foo', 'python')
>>> items[1]
('bar', 'spam')
list(d.items())
list(d.items())
usando next(islice(d.items(), 1))
para obter('bar', 'spam')
Você precisa usar um OrderedDict ou deseja especificamente um tipo de mapa que é ordenado de alguma forma com indexação posicional rápida? Se este for o caso, considere um dos muitos tipos de ditado classificado do Python (que ordena pares de valor-chave com base na ordem de classificação). Algumas implementações também oferecem suporte à indexação rápida. Por exemplo, o projeto de contêineres classificados possui um tipo SortedDict para esse fim.
>>> 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
com uma função de tecla para evitar comparações. Como: SortedDict(lambda key: 0, ...)
. As chaves serão desordenadas, mas permanecerão em uma ordem estável e são indexáveis.
Aqui está um caso especial se você deseja a primeira entrada (ou próxima a ela) em um OrderedDict, sem criar uma lista. (Isso foi atualizado para o 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'
(A primeira vez que você diz "next ()", significa realmente "primeiro".)
No meu teste informal, next(iter(d.items()))
com um pequeno OrderedDict é apenas um pouquinho mais rápido que items()[0]
. Com um OrderedDict de 10.000 entradas, next(iter(d.items()))
foi cerca de 200 vezes mais rápido que items()[0]
.
MAS, se você salvar a lista de itens () uma vez e depois usá-la muito, isso poderá ser mais rápido. Ou se você repetidamente {criar um iterador de itens () e percorrê-lo para a posição desejada}, isso poderá ser mais lento.
OrderedDict
s não tem um iteritems()
método, então você vai precisar fazer o seguinte, a fim de obter o primeiro item: next(iter(d.items()))
.
d.items()
não parece ser um iterador, então o iter na frente não ajudará? Ele ainda retornará a lista completa :(
odict_iterator
e me foi confirmado no IRC #python que isso não faz uma cópia da lista.
É muito mais eficiente usar o IndexedOrderedDict do indexed
pacote.
Após o comentário de Niklas, fiz um benchmark no OrderedDict e IndexedOrderedDict com 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 é ~ 100 vezes mais rápido nos elementos de indexação em uma posição específica nesse caso específico.
indexed.py
vez de indexed
.
Este wiki da comunidade tenta coletar respostas existentes.
Python 2.7
Em python 2, as keys()
, values()
e items()
funções de OrderedDict
listas de retorno. Usando values
como exemplo, a maneira mais simples é
d.values()[0] # "python"
d.values()[1] # "spam"
Para grandes coleções onde você só se preocupam com um único índice, você pode evitar criar a lista completa usando as versões do gerador, iterkeys
, itervalues
e iteritems
:
import itertools
next(itertools.islice(d.itervalues(), 0, 1)) # "python"
next(itertools.islice(d.itervalues(), 1, 2)) # "spam"
O pacote indexed.py fornece IndexedOrderedDict
, projetado para esse caso de uso e será a opção mais rápida.
from indexed import IndexedOrderedDict
d = IndexedOrderedDict({'foo':'python','bar':'spam'})
d.values()[0] # "python"
d.values()[1] # "spam"
O uso de itervalues pode ser consideravelmente mais rápido para dicionários grandes com acesso aleatório:
$ 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
O Python 3 tem as mesmas duas opções básicas (lista versus gerador), mas os métodos dict retornam geradores por padrão.
Método de lista:
list(d.values())[0] # "python"
list(d.values())[1] # "spam"
Método gerador:
import itertools
next(itertools.islice(d.values(), 0, 1)) # "python"
next(itertools.islice(d.values(), 1, 2)) # "spam"
Os dicionários do Python 3 são uma ordem de magnitude mais rápida que o python 2 e têm acelerações semelhantes para usar geradores.
+--------+-----------+----------------+---------+
| size | list (ms) | generator (ms) | indexed |
+--------+-----------+----------------+---------+
| 1000 | .0316 | .0165 | .00262 |
| 10000 | .288 | .166 | .00294 |
| 100000 | 3.53 | 1.48 | .00332 |
+--------+-----------+----------------+---------+
É uma nova era e, com os dicionários Python 3.6.1, agora eles mantêm sua ordem. Essa semântica não é explícita porque isso exigiria a aprovação do BDFL. Mas Raymond Hettinger é a próxima melhor coisa (e engraçado) e ele faz uma muito forte caso que os dicionários serão ordenados por um tempo muito longo.
Então agora é fácil criar fatias de um dicionário:
test_dict = {
'first': 1,
'second': 2,
'third': 3,
'fourth': 4
}
list(test_dict.items())[:2]
Nota: A preservação dictonária de ordem de inserção agora é oficial no Python 3.7 .
para OrderedDict (), você pode acessar os elementos indexando obtendo as tuplas dos pares (chave, valor) da seguinte forma ou 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 retorna um objeto de exibição de dicionário interável em vez de uma lista e não oferece suporte a fatias ou indexação. Então você teria que transformá-lo em uma lista primeiro. docs.python.org/3.3/library/stdtypes.html#dict-views