Accesso all'elemento dict_keys per indice in Python3


131

Sto provando ad accedere a un elemento di dict_key tramite il suo indice:

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

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

Voglio ottenere foo.

Lo stesso con:

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

Come posso fare questo?


9
In py3.x dict.keys()restituisce un set come oggetto vista, non elenco (quindi l'indicizzazione non è possibile). Usakeys = list(test)
Ashwini Chaudhary il

quando faccio list (qualcosa_dict), l'ordine delle tuple è casuale: esempio: list ({'foo': 'bar', 'hello': 'world'}) può restituire: list (foo, ciao) o list (ciao, pippo), perché è casuale?
fj123x,

7
I dicts non hanno alcun ordine (utilizzare collections.OrderedDictse si desidera ordinare le chiavi)
Ashwini Chaudhary,

Interessante discussione sulla sicurezza dei thread qui riaffermando i vari approcci per risolvere questo problema: blog.labix.org/2008/06/27/…
Paul

Risposte:


161

Chiama list()invece il dizionario:

keys = list(test)

In Python 3, il dict.keys()metodo restituisce un oggetto vista dizionario , che funge da set. L'iterazione diretta nel dizionario produce anche chiavi, quindi la trasformazione di un dizionario in un elenco risulta in un elenco di tutte le chiavi:

>>> test = {'foo': 'bar', 'hello': 'world'}
>>> list(test)
['foo', 'hello']
>>> list(test)[0]
'foo'

3
Fai attenzione all'elenco (dict.keys ()) in Python 3 - Labix Blog spiega chiaramente qual è il problema senza fornire una soluzione. Questo è eccellente!
Brandon Bradley,

@BrandonBradley: in generale: fare affidamento sul fatto che certe azioni siano atomiche è comunque una cattiva idea, dato che Python è molto dinamico. È possibile passare facilmente una dictsottoclasse al codice , ad esempio, dove .keys()viene gestito nel codice Python (ad esempio può avvenire un cambio di thread).
Martijn Pieters

@BrandonBradley: grazie per il link. Solo la soluzione di uno dei commenti per quel blog funziona per me in Python3: sort (dict.keys ()). In Python2, dict.keys () restituirà un elenco di valori chiave.
Buona volontà

2
@GoodWill: sorted(dict)farebbe esattamente la stessa cosa; produce un elenco di chiavi in ​​ordine ordinato. list(dict)ti darà l'elenco in ordine di dizionario.
Martijn Pieters

1
o da usarekeys = [*test]
Alex78191 del

59

Non una risposta completa ma forse un suggerimento utile. Se è davvero il primo oggetto che desideri *, allora

next(iter(q))

è molto più veloce di

list(q)[0]

per grandi dadi, poiché non è necessario archiviare l'intera memoria.

Per 10.000.000 di articoli l'ho trovato quasi 40.000 volte più veloce.

* Il primo oggetto nel caso in cui un dict fosse solo un oggetto pseudo-casuale prima di Python 3.6 (dopo che è stato ordinato nell'implementazione standard, anche se non è consigliato fare affidamento su di esso).


5
Questo è sempre stato uno dei miei maggiori problemi con tutto ciò che diventa iteratore in Py3. È sicuramente più efficiente, ma molti casi d'uso diventano "sporchi" e complicati senza motivo. Ad esempio, perché non possono semplicemente supportare l'indicizzazione sull'iteratore, senza necessariamente avere una perdita di prestazioni?
Ehsan Kia,

2

Volevo una coppia "chiave" e "valore" di un primo elemento del dizionario. Ho usato il seguente codice.

 key, val = next(iter(my_dict.items()))

0
test = {'foo': 'bar', 'hello': 'world'}
ls = []
for key in test.keys():
    ls.append(key)
print(ls[0])

Modo convenzionale di aggiungere le chiavi a un elenco definito staticamente e quindi indicizzarlo per lo stesso


2
Non è sbagliato, ma perché no ls = list(test.keys())? Lo trovo più semplice.
Valentino,

Sì, questo è più efficiente. Ho scritto questo solo per mostrare la leggibilità.
pranav dua,

0

In molti casi, questo potrebbe essere un problema XY . Perché stai indicizzando le chiavi del tuo dizionario in base alla posizione? Ne hai davvero bisogno? Fino a poco tempo fa, i dizionari non erano nemmeno ordinati in Python, quindi l'accesso al primo elemento era arbitrario.

Ho appena tradotto del codice Python 2 in Python 3:

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

che non è carino, ma neanche molto male. All'inizio, stavo per sostituirlo con il mostruoso

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

prima ho capito che è tutto molto meglio scritto come

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

che funziona bene.

Credo che in molti altri casi si possa evitare di indicizzare le chiavi del dizionario per posizione. Sebbene i dizionari siano ordinati in Python 3.7, basarsi su quello non è carino. Il codice sopra funziona solo perché il contenuto di è some_liststato recentemente prodotto dal contenuto di d.

Dai un'occhiata al tuo codice se hai davvero bisogno di accedere a un disk_keyselemento per indice. Forse non è necessario.


0

Prova questo

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

Il risultato è simile a questo. ['pippo', 'ciao']

Puoi trovare altre soluzioni possibili qui .

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.