Dostęp do elementu dict_keys przez indeks w Python3


131

Próbuję uzyskać dostęp do elementu dict_key przez jego indeks:

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

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

Chcę dostać foo.

tak samo z:

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

W jaki sposób mogę to zrobić?


9
W py3.x dict.keys()zwraca zestaw, taki jak obiekt widoku, a nie lista (więc indeksowanie nie jest możliwe). Użyjkeys = list(test)
Ashwini Chaudhary

kiedy robię list (something_dict), kolejność krotek jest losowa: przykład: list ({'foo': 'bar', 'hello': 'world'}) może zwracać: list (foo, hello) lub list (hello, foo), dlaczego jest to przypadkowe?
fj123x

7
Dicts nie mają żadnego zamówienia (użyj, collections.OrderedDictjeśli chcesz zamówić klucze)
Ashwini Chaudhary

Ciekawa dyskusja na temat bezpieczeństwa wątków przedstawiająca różne podejścia do rozwiązania tego problemu: blog.labix.org/2008/06/27/...
Paul

Odpowiedzi:


161

list()Zamiast tego zadzwoń do słownika:

keys = list(test)

W Pythonie 3 dict.keys()metoda zwraca obiekt widoku słownika , który działa jak zestaw. Iterowanie bezpośrednio po słowniku również daje klucze, więc przekształcenie słownika w listę powoduje wyświetlenie listy wszystkich kluczy:

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

3
Uważaj na listę (dict.keys ()) w Pythonie 3 - Blog Labix jasno wyjaśnia, na czym polega problem, nie podając rozwiązania. To jest wspaniałe!
Brandon Bradley

@BrandonBradley: ogólnie mówiąc: poleganie na atomowych działaniach i tak jest złym pomysłem, ponieważ Python jest bardzo dynamiczny. Twój kod może być łatwo przekazany do dictpodklasy, na przykład, gdzie .keys()jest obsługiwany w kodzie Pythona (np. Może nastąpić przełączenie wątku).
Martijn Pieters

@BrandonBradley: dzięki za link. Tylko rozwiązanie z jednego z komentarzy do tego bloga działa dla mnie w Python3: sortowane (dict.keys ()). W Python2 dict.keys () zwróci listę wartości kluczy.
Dobra wola

2
@GoodWill: sorted(dict)zrobiłby dokładnie to samo; tworzy listę kluczy w posortowanej kolejności. list(dict)wyświetli listę w kolejności słownikowej.
Martijn Pieters

1
lub użyćkeys = [*test]
Alex78191,

59

Nie jest to pełna odpowiedź, ale być może przydatna wskazówka. Jeśli to naprawdę pierwszy przedmiot, który chcesz *, to

next(iter(q))

jest znacznie szybszy niż

list(q)[0]

dla dużych dykt, ponieważ całość nie musi być przechowywana w pamięci.

Dla 10 000 000 pozycji okazało się, że jest to prawie 40 000 razy szybsze.

* Pierwsza pozycja w przypadku, gdy dict jest tylko pseudolosowym elementem przed Pythonem 3.6 (później jest uporządkowany w standardowej implementacji, chociaż nie zaleca się na nim polegać).


5
To zawsze był jeden z moich największych problemów, ponieważ wszystko stało się iteratorami w Py3. Jest zdecydowanie bardziej wydajna, ale tak wiele przypadków użycia staje się „nieczystych” i komplikuje się bez powodu. Na przykład, dlaczego nie mogą po prostu obsługiwać indeksowania w iteratorze, niekoniecznie powodując utratę wydajności?
Ehsan Kia,

2

Chciałem pary „klucz” i „wartość” pierwszego elementu słownika. Użyłem następującego kodu.

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

Konwencjonalny sposób dołączania kluczy do statycznie zdefiniowanej listy, a następnie indeksowania jej dla tego samego


2
Nie jest źle, ale dlaczego nie ls = list(test.keys())? Uważam to za prostsze.
Valentino,

Tak, to jest bardziej wydajne. Napisałem to tylko po to, aby pokazać czytelność.
pranav dua

0

W wielu przypadkach może to być problem XY . Dlaczego indeksujesz klucze słownika według pozycji? Czy naprawdę potrzebujesz? Do niedawna słowniki nie były nawet porządkowane w Pythonie, więc dostęp do pierwszego elementu był dowolny.

Właśnie przetłumaczyłem kod Pythona 2 na Python 3:

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

co nie jest ładne, ale też niezbyt złe. Na początku miałem zamiar go zastąpić potwornym

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

zanim zdałem sobie sprawę, że to wszystko jest znacznie lepiej napisane jako

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

który działa dobrze.

Uważam, że w wielu innych przypadkach można uniknąć indeksowania kluczy słownika według pozycji. Chociaż słowniki są uporządkowane w Pythonie 3.7, poleganie na tym nie jest ładne. Powyższy kod działa tylko dlatego, że zawartość some_listzostała niedawno utworzona na podstawie zawartości d.

Przyjrzyj się dokładnie swojemu kodowi, jeśli naprawdę potrzebujesz dostępu do disk_keyselementu według indeksu. Być może nie musisz.


0

Spróbuj tego

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

Wynik wygląda następująco. [„foo”, „cześć”]

Więcej możliwych rozwiązań znajdziesz tutaj .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.