Co oznacza enumerate ()?

Odpowiedzi:

513

enumerate()Funkcja dodaje licznik do iterable.

Tak więc dla każdego elementu cursorjest tworzona krotka (counter, element); że forwiąże się pętla row_numberi rowodpowiednio.

Próbny:

>>> elements = ('foo', 'bar', 'baz')
>>> for elem in elements:
...     print elem
... 
foo
bar
baz
>>> for count, elem in enumerate(elements):
...     print count, elem
... 
0 foo
1 bar
2 baz

Domyślnie enumerate()zaczyna się od, 0ale jeśli podasz mu drugi argument liczby całkowitej, zacznie się od tej liczby:

>>> for count, elem in enumerate(elements, 42):
...     print count, elem
... 
42 foo
43 bar
44 baz

Jeśli chcesz ponownie wdrożyć enumerate()w Pythonie, oto dwa sposoby na osiągnięcie tego; jeden używa itertools.count()do zliczania, drugi ręcznie zlicza w funkcji generatora :

from itertools import count

def enumerate(it, start=0):
    # return an iterator that adds a counter to each element of it
    return zip(count(start), it)

i

def enumerate(it, start=0):
    count = start
    for elem in it:
        yield (count, elem)
        count += 1

Rzeczywistego wykonania w C jest bliżej drugi z optymalizacji ponowne wykorzystanie pojedynczego obiektu krotny dla wspólnych for i, ...rozpakowaniu obudowy i stosując standardowe wartości C całkowitą licznika dopóki licznik staje się zbyt duża, aby uniknąć stosując całkowitą obiekt Pythona (co jest bezgraniczny).

Martijn Pieters
źródło
92

Jest to wbudowana funkcja, która zwraca obiekt, który można iterować. Zobacz dokumentację .

Krótko mówiąc, zapętla elementy iterowalne (takie jak lista), a także numer indeksu, połączone w krotkę:

for item in enumerate(["a", "b", "c"]):
    print item

odciski

(0, "a")
(1, "b")
(2, "c")

Jest to pomocne, jeśli chcesz zapętlić sekwencję (lub inną iterowalną rzecz), a także chcesz mieć dostępny licznik indeksów. Jeśli chcesz, aby licznik zaczynał od innej wartości (zwykle 1), możesz podać to jako drugi argument enumerate.

RemcoGerlich
źródło
1
jeśli dodasz drugą zmienną item, możesz usunąć nawias: D
Abdelouahab
2
Pedantyczny: Jest to funkcja zwracająca iterator, a nie generator. Generatory to określona klasa funkcji zdefiniowanych przez użytkownika (wykorzystujących yield/ yield fromlub wyrażenia generatora, które domyślnie yield); enumeratenie jest generatorem. Dla wszystkich celów związanych z pisaniem kaczek nie ma różnicy, ale jawne sprawdzanie typów i dokumenty języka Python używają terminu „generator” tylko w jednym celu, który nie obejmuje enumerate.
ShadowRanger
22

Czytam książkę ( Effective Python ) Bretta Slatkina, który pokazuje inny sposób iteracji po liście, a także zna indeks bieżącego elementu na liście, ale sugeruje, że lepiej nie używać go, a enumeratezamiast tego używać . Wiem, że spytałeś, co oznacza wyliczenie, ale kiedy zrozumiałem następujące, zrozumiałem także, w jaki sposób enumerateiteracja po liście jest łatwiejsza (i bardziej czytelna).

list_of_letters = ['a', 'b', 'c']
for i in range(len(list_of_letters)):
    letter = list_of_letters[i]
    print (i, letter)

Dane wyjściowe to:

0 a
1 b
2 c

Ja też kiedyś coś robiłem, nawet głupszy, zanim przeczytałem o tej enumeratefunkcji.

i = 0
for n in list_of_letters:
    print (i, n)
    i += 1

Daje to samo wyjście.

Ale enumeratepo prostu muszę napisać:

list_of_letters = ['a', 'b', 'c']
for i, letter in enumerate(list_of_letters):
    print (i, letter)
Dora
źródło
20

Jak wspomnieli inni użytkownicy, enumeratejest generatorem, który dodaje przyrostowy indeks obok każdego elementu iterowalnego.

Więc jeśli masz listę powiedzenia l = ["test_1", "test_2", "test_3"]The list(enumerate(l))daje coś takiego: [(0, 'test_1'), (1, 'test_2'), (2, 'test_3')].

Kiedy to jest przydatne? Możliwym przypadkiem użycia jest sytuacja, gdy chcesz iterować elementy i chcesz pominąć konkretny element, który znasz tylko jego indeks na liście, ale nie jego wartość (ponieważ jego wartość nie jest w tym czasie znana).

for index, value in enumerate(joint_values):
   if index == 3:
       continue

   # Do something with the other `value`

Więc twój kod czyta lepiej, ponieważ możesz również wykonywać regularne pętle for, rangeale aby uzyskać dostęp do elementów, musisz je zindeksować (tj joint_values[i].).

Chociaż inny użytkownik wspomniał o implementacji enumerateużywania zip, myślę, że bardziej czysty (ale nieco bardziej złożony) sposób bez użycia itertoolsjest następujący:

def enumerate(l, start=0):
    return zip(range(start, len(l) + start), l)

Przykład:

l = ["test_1", "test_2", "test_3"]
enumerate(l)
enumerate(l, 10)

Wynik:

[(0, „test_1”), (1, „test_2”), (2, „test_3”)]

[(10, „test_1”), (11, „test_2”), (12, „test_3”)]

Jak wspomniano w komentarzach, to podejście z zakresem nie będzie działać z dowolnymi iterowalnymi enumeratefunkcjami, jak działa funkcja oryginalna .

Rafael
źródło
Inną odpowiedzią itertoolsjest to, że twoje rangepodejście działa tylko z kontenerami. enumeratewspółpracuje z dowolnymi iteracjami; jeśli chcesz iterować plik, for lineno, line in enumerate(myfile):działa, ale nie możesz tego zrobić, range(len(myfile))ponieważ długość nie jest znana, dopóki nie osiągniesz EOF.
ShadowRanger
12

Funkcja wyliczenia działa w następujący sposób:

doc = """I like movie. But I don't like the cast. The story is very nice"""
doc1 = doc.split('.')
for i in enumerate(doc1):
     print(i)

Dane wyjściowe to

(0, 'I like movie')
(1, " But I don't like the cast")
(2, ' The story is very nice')
Ashok Kumar Jayaraman
źródło