Accéder à l'élément dict_keys par index en Python3


131

J'essaie d'accéder à l'élément d'un dict_key par son index:

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

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

Je veux avoir foo.

même avec:

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

Comment puis-je faire ceci?


9
Dans py3.x dict.keys()renvoie un ensemble comme un objet de vue, pas une liste (donc, l'indexation n'est pas possible). Utilisationkeys = list(test)
Ashwini Chaudhary

quand je fais list (something_dict), l'ordre des tuple est aléatoire: exemple: list ({'foo': 'bar', 'hello': 'world'}) peut retourner: list (foo, hello) ou list (hello, toto), pourquoi est-ce aléatoire?
fj123x

7
Les dictionnaires n'ont aucune commande . (À utiliser collections.OrderedDictsi vous voulez des clés commandées)
Ashwini Chaudhary

Discussion intéressante sur la sécurité des threads ici réaménageant les différentes approches pour résoudre ce problème: blog.labix.org/2008/06/27
Paul

Réponses:


161

Appelez list()plutôt le dictionnaire:

keys = list(test)

Dans Python 3, la dict.keys()méthode renvoie un objet de vue dictionnaire , qui agit comme un ensemble. Itérer directement sur le dictionnaire produit également des clés, donc transformer un dictionnaire en une liste entraîne une liste de toutes les clés:

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

3
Surveillez la liste (dict.keys ()) dans Python 3 - Labix Blog explique clairement quel est le problème sans fournir de solution. C'est excellent!
Brandon Bradley

@BrandonBradley: de manière générale: se fier à certaines actions comme étant atomiques est de toute façon une mauvaise idée, car Python est tellement dynamique. Votre code peut facilement être passé dans une dictsous - classe, par exemple, où .keys()est géré dans le code Python (par exemple, un changement de thread peut avoir lieu).
Martijn Pieters

@BrandonBradley: merci pour le lien. Seule la solution de l'un des commentaires de ce blog fonctionne pour moi dans Python3: trié (dict.keys ()). En Python2, dict.keys () renverra une liste de valeurs clés.
Bonne volonté

2
@GoodWill: sorted(dict)ferait exactement la même chose; produire une liste de clés dans un ordre trié. list(dict)vous donnera la liste dans l'ordre du dictionnaire.
Martijn Pieters

1
ou à utiliserkeys = [*test]
Alex78191

59

Pas une réponse complète mais peut-être un indice utile. Si c'est vraiment le premier article que vous voulez *, alors

next(iter(q))

est beaucoup plus rapide que

list(q)[0]

pour les grands dictats, car le tout n'a pas à être stocké en mémoire.

Pour 10 000 000 articles, je l'ai trouvé presque 40 000 fois plus rapide.

* Le premier élément dans le cas d'un dict étant juste un élément pseudo-aléatoire avant Python 3.6 (après cela, il est ordonné dans l'implémentation standard, bien qu'il ne soit pas conseillé de s'y fier).


5
Cela a toujours été l'un de mes plus gros problèmes avec tout ce qui devient des itérateurs dans Py3. C'est certainement plus efficace, mais de nombreux cas d'utilisation deviennent «impurs» et compliqués sans raison. Par exemple, pourquoi ne peuvent-ils pas simplement prendre en charge l'indexation sur l'itérateur, sans nécessairement avoir une perte de performances?
Ehsan Kia

2

Je voulais une paire «clé» et «valeur» d'un premier élément du dictionnaire. J'ai utilisé le code suivant.

 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])

Méthode conventionnelle pour ajouter les clés à une liste définie statiquement, puis l'indexer pour celle-ci


2
Ce n'est pas faux, mais pourquoi pas ls = list(test.keys())? Je trouve cela plus simple.
Valentino

Oui, c'est plus efficace. J'ai écrit ceci juste pour montrer la lisibilité.
pranav dua

0

Dans de nombreux cas, cela peut être un problème XY . Pourquoi indexez-vous vos clés de dictionnaire par position? En avez-vous vraiment besoin? Jusqu'à récemment, les dictionnaires n'étaient même pas classés en Python, donc l'accès au premier élément était arbitraire.

Je viens de traduire du code Python 2 en Python 3:

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

ce qui n'est pas joli, mais pas très mal non plus. Au début, j'allais le remplacer par le monstrueux

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

avant de réaliser que tout cela est bien mieux écrit comme

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

qui fonctionne très bien.

Je pense que dans de nombreux autres cas, l'indexation des clés du dictionnaire par position peut être évitée. Bien que les dictionnaires soient ordonnés dans Python 3.7, s'en remettre à cela n'est pas joli. Le code ci-dessus ne fonctionne que parce que le contenu de some_lista été récemment produit à partir du contenu de d.

Jetez un œil à votre code si vous avez vraiment besoin d'accéder à un disk_keysélément par index. Vous n'en avez peut-être pas besoin.


0

Essaye ça

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

Le résultat ressemble à ceci. ['toto', 'bonjour']

Vous pouvez trouver plus de solutions possibles ici .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.