Acessando o elemento dict_keys pelo índice em Python3

131

Eu estou tentando acessar o elemento de um dict_key pelo seu índice:

test = {'foo': 'bar', 'hello': 'world'}
keys = test.keys()  # dict_keys object

keys.index(0)
AttributeError: 'dict_keys' object has no attribute 'index'

Eu quero pegar foo.

mesmo com:

keys[0]
TypeError: 'dict_keys' object does not support indexing

Como posso fazer isso?

fj123x
fonte
9
Em py3.x dict.keys()retorna um conjunto como objeto de visualização, não lista (portanto, a indexação não é possível). Usekeys = list(test)
Ashwini Chaudhary
quando faço list (something_dict), a ordem da tupla é aleatória: exemplo: list ({'foo': 'bar', 'olá': 'world'}) pode retornar: list (foo, olá) ou list (olá, foo), por que isso é aleatório?
Fj123x
7
Dicts não têm qualquer ordem (Use. collections.OrderedDictSe você quiser chaves ordenadas)
Ashwini Chaudhary
Interessante discussão sobre a segurança do thread aqui Reagrding as várias abordagens para resolver este problema: blog.labix.org/2008/06/27/...
Paul

Respostas:

161

Invoque list()o dicionário:

keys = list(test)

No Python 3, o dict.keys()método retorna um objeto de exibição de dicionário , que atua como um conjunto. A iteração direta sobre o dicionário também produz chaves, portanto, transformar um dicionário em uma lista resulta em uma lista de todas as chaves:

>>> test = {'foo': 'bar', 'hello': 'world'}
>>> list(test)
['foo', 'hello']
>>> list(test)[0]
'foo'
Martijn Pieters
fonte
3
Cuidado com a lista (dict.keys ()) no Python 3 - Labix Blog explica claramente qual é o problema sem fornecer uma solução. Isto e excelente!
Brandon Bradley
@BrandonBradley: de um modo geral: confiar em certas ações sendo atômicas é uma péssima ideia, já que o Python é muito dinâmico. Seu código pode ser facilmente passado para uma dictsubclasse, por exemplo, onde .keys()é tratado no código Python (por exemplo, uma troca de thread pode ocorrer).
Martijn Pieters
@BrandonBradley: obrigado pelo link. Somente a solução de um dos comentários desse blog funciona para mim no Python3: ordenada (dict.keys ()). No Python2, dict.keys () retornará uma lista de valores-chave.
Boa Vontade
2
@ GoodWill: sorted(dict)faria exatamente a mesma coisa; produz uma lista de chaves em ordem classificada. list(dict)fornecerá a lista em ordem de dicionário.
Martijn Pieters
1
ou pode usarkeys = [*test]
Alex78191
59

Não é uma resposta completa, mas talvez uma dica útil. Se é realmente o primeiro item que você deseja *, então

next(iter(q))

é muito mais rápido que

list(q)[0]

para ditados grandes, já que a coisa toda não precisa ser armazenada na memória.

Para 10.000.000 itens, achei quase 40.000 vezes mais rápido.

* O primeiro item no caso de um dict ser apenas um item pseudo-aleatório antes do Python 3.6 (depois disso, é ordenado na implementação padrão, embora não seja aconselhável confiar nele).

Marca
fonte
5
Esse sempre foi um dos meus maiores problemas, com tudo se tornando iteradores no Py3. É definitivamente mais eficiente, mas muitos casos de uso se tornam "impuros" e complicados sem motivo. Por exemplo, por que eles não podem simplesmente suportar a indexação no iterador, sem necessariamente ter uma perda de desempenho?
Ehsan Kia
2

Eu queria o par "chave" e "valor" de um primeiro item do dicionário. Eu usei o seguinte código.

 key, val = next(iter(my_dict.items()))
Sheikh Abdul Wahid
fonte
0
test = {'foo': 'bar', 'hello': 'world'}
ls = []
for key in test.keys():
    ls.append(key)
print(ls[0])

Maneira convencional de anexar as chaves a uma lista definida estaticamente e depois indexá-la pela mesma

pranav dua
fonte
2
Não está errado, mas por que não ls = list(test.keys())? Eu acho isso mais simples.
Valentino
Sim, isso é mais eficiente. Eu escrevi isso apenas para mostrar a legibilidade.
pranav dua
0

Em muitos casos, isso pode ser um problema XY . Por que você está indexando as chaves do seu dicionário por posição? Você realmente precisa? Até recentemente, os dicionários nem sequer eram ordenados em Python, portanto, acessar o primeiro elemento era arbitrário.

Acabei de traduzir um código Python 2 para Python 3:

keys = d.keys()
for (i, res) in enumerate(some_list):
    k = keys[i]
    # ...

o que não é bonito, mas também não é muito ruim. No começo, eu estava prestes a substituí-lo pela monstruosa

    k = next(itertools.islice(iter(keys), i, None))

antes que eu percebesse isso tudo é muito melhor escrito como

for (k, res) in zip(d.keys(), some_list):

o que funciona muito bem.

Acredito que em muitos outros casos, a indexação das chaves do dicionário por posição pode ser evitada. Embora os dicionários sejam ordenados no Python 3.7, confiar nisso não é bonito. O código acima funciona apenas porque o conteúdo desome_list foi produzido recentemente a partir do conteúdo de d.

Dê uma olhada no seu código, se você realmente precisar acessar um disk_keyselemento pelo índice. Talvez você não precise.

gerrit
fonte
0

Tente isto

keys = [next(iter(x.keys())) for x in test]
print(list(keys))

O resultado é assim. ['foo', 'olá']

Você pode encontrar mais soluções possíveis aqui .

Shirantha Madusanka
fonte