Tego typu wyrażenia często można znaleźć w pytaniach Pythona dotyczących SO. Albo po prostu uzyskać dostęp do wszystkich elementów iterowalnej
for i in range(len(a)):
print(a[i])
Co jest po prostu nieporęcznym sposobem pisania:
for e in a:
print(e)
Lub do przypisywania do elementów iterowalnych:
for i in range(len(a)):
a[i] = a[i] * 2
Która powinna być taka sama jak:
for i, e in enumerate(a):
a[i] = e * 2
# Or if it isn't too expensive to create a new iterable
a = [e * 2 for e in a]
Lub do filtrowania indeksów:
for i in range(len(a)):
if i % 2 == 1: continue
print(a[i])
Który można wyrazić w ten sposób:
for e in a [::2]:
print(e)
Lub gdy potrzebujesz tylko długości listy, a nie jej zawartości:
for _ in range(len(a)):
doSomethingUnrelatedToA()
Który może być:
for _ in a:
doSomethingUnrelatedToA()
W Pythonie mamy enumerate
, krojenie, filter
, sorted
, itd ... jak Python for
konstrukcje są przeznaczone do iteracyjnego iterables i to nie tylko w zakresie liczb całkowitych, czy są rzeczywistym świecie używa-przypadki, gdzie trzeba in range(len(a))
?
range(len(a))
zwykle są to ludzie, którzy nie mają doświadczenia w Pythonie (chociaż niekoniecznie w ogóle w programowaniu).range(len(a))
wtedy, gdy uczyłem się Pythona. Obecnie nie robię tego, ponieważ, jak powiedziałeś, dość łatwo jest go wymienić.range(len(a))
często, bo nie potrzebuję zawartości listy a, tylko długość.for i in range(len(a)): doSomethingAbout(a[i+1] - a[i])
Jak to obejść?Odpowiedzi:
Jeśli potrzebujesz pracować z indeksami ciągu, to tak - używasz go ... np. Jako odpowiednik numpy.argsort ...:
>>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0]
źródło
[ix for ix, _ in sorted(enumerate(a), key=lambda i: i[1])]
chociaż, chociaż twój jest prawdopodobnie ładniejszy / bardziej geekowy.A jeśli potrzebujesz dostępu do dwóch elementów listy jednocześnie?
for i in range(len(a[0:-1])): something_new[i] = a[i] * a[i+1]
Możesz tego użyć, ale prawdopodobnie jest to mniej jasne:
for i, _ in enumerate(a[0:-1]): something_new[i] = a[i] * a[i+1]
Osobiście nie jestem z żadnego w 100% zadowolony!
źródło
for ix, i in enumerate(a)
wydaje się być równoważne, nie?for a1,a2 in zip(a[:-1],a[1:])
Krótka odpowiedź : mówiąc matematycznie nie, w praktyce tak, na przykład w przypadku programowania intencjonalnego.
Technicznie rzecz biorąc, odpowiedź brzmiałaby „nie, nie jest to potrzebne”, ponieważ można to wyrazić za pomocą innych konstrukcji. Ale w praktyce używam
for i in range(len(a)
(lubfor _ in range(len(a))
jeśli nie potrzebuję indeksu), aby wyraźnie zaznaczyć, że chcę iterować tyle razy, ile jest elementów w sekwencji, bez konieczności używania elementów w sekwencji do niczego.Więc: "Czy jest taka potrzeba?" ? - tak, potrzebuję go do wyrażenia znaczenia / przeznaczenia kodu ze względu na czytelność.
Zobacz też: https://en.wikipedia.org/wiki/Intentional_programming
I oczywiście, jeśli w ogóle nie ma kolekcji, która jest powiązana z iteracją,
for ... in range(len(N))
jest to jedyna opcja, aby nie uciekać się doi = 0; while i < N; i += 1 ...
źródło
for _ in range(len(a))
ponadfor _ in a
?a
„ w przeciwieństwie do ”dla każdego element wa
, niezależnie od zawartościa
„ ... więc tylko niuans w programowaniu intencjonalnym.'hello'
zawierającą tyle pozycji, ile na liściea
, użyjb = ['hello'] * len(a)
Idąc przez komentarze, a także osobistego doświadczenia, ja nie powiedzieć, nie ma potrzeby do
range(len(a))
. Wszystko, co możesz zrobić,range(len(a))
możesz zrobić w inny (zwykle znacznie bardziej efektywny) sposób.Podałeś wiele przykładów w swoim poście, więc nie będę ich tutaj powtarzał. Zamiast tego podam przykład dla tych, którzy mówią: „A jeśli chcę tylko długości
a
, a nie elementów?”. To jeden z niewielu przypadków, w których możesz rozważyć użycierange(len(a))
. Jednak nawet to można zrobić w następujący sposób:>>> a = [1, 2, 3, 4] >>> for _ in a: ... print True ... True True True True >>>
Odpowiedź Clementsa (jak pokazuje Allik) można również przerobić, aby usunąć
range(len(a))
:>>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0] >>> # Note however that, in this case, range(len(a)) is more efficient. >>> [x for x, _ in sorted(enumerate(a), key=lambda i: i[1])] [2, 3, 1, 5, 4, 0] >>>
Podsumowując,
range(len(a))
nie jest potrzebne . Jedynym plusem jest czytelność (intencja jest jasna). Ale to tylko preferencje i styl kodu.źródło
for _ in a:
jako „Iteruję po a, ale ignoruję jego zawartość”, ale interpretujęfor _ in range(len(a))
jako „Uzyskaj długość a, następnie tworzę liczbę liczb całkowitych o tej samej długości, a na koniec ignoruję zawartość”.range(len(a))
scenariusza „Muszę użyć albo nie mogę tego zrobić”.Czasami matplotlib wymaga
range(len(y))
np. Whiley=array([1,2,5,6])
,plot(y)
działa dobrze,scatter(y)
a nie. Trzeba pisaćscatter(range(len(y)),y)
. (Osobiście uważam, że to błądscatter
;plot
i jego przyjaciółscatter
istem
powinni używać tych samych sekwencji wywołań tak często, jak to możliwe.)źródło
Dobrze jest mieć, gdy potrzebujesz użyć indeksu do jakiejś manipulacji, a posiadanie bieżącego elementu nie wystarczy. Weźmy na przykład drzewo binarne, które jest przechowywane w tablicy. Jeśli masz metodę, która prosi o zwrócenie listy krotek, która zawiera bezpośrednie dzieci każdego węzła, potrzebujesz indeksu.
#0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ... nodes = [0,1,2,3,4,5,6,7,8,9,10] children = [] for i in range(len(nodes)): leftNode = None rightNode = None if i*2 + 1 < len(nodes): leftNode = nodes[i*2 + 1] if i*2 + 2 < len(nodes): rightNode = nodes[i*2 + 2] children.append((leftNode,rightNode)) return children
Oczywiście, jeśli element, nad którym pracujesz, jest obiektem, możesz po prostu wywołać metodę get children. Ale tak, naprawdę potrzebujesz indeksu tylko wtedy, gdy wykonujesz jakąś manipulację.
źródło
Mam przypadek użycia, którego nie wydaje mi się żaden z twoich przykładów.
boxes = [b1, b2, b3] items = [i1, i2, i3, i4, i5] for j in range(len(boxes)): boxes[j].putitemin(items[j])
Jestem stosunkowo nowy w Pythonie, ale cieszę się, że mogę nauczyć się bardziej eleganckiego podejścia.
źródło
[a - b for a, b in zip(list1, list2)]
jest o wiele ładniejszy niż[list1[i] - list2[i] for i in range(len(list1))]
… Dzięki!Jeśli musisz iterować po pierwszych
len(a)
elementach obiektub
(czyli większych niża
), prawdopodobnie powinieneś użyćrange(len(a))
:for i in range(len(a)): do_something_with(b[i])
źródło
for b_elem in b[:len(a)]:...
itertools.islice
zamiast tego.Czasami naprawdę nie przejmujesz się samą kolekcją . Na przykład utworzenie prostej linii dopasowania modelu w celu porównania „przybliżenia” z surowymi danymi:
fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Fibonacci numbers phi = (1 + sqrt(5)) / 2 phi2 = (1 - sqrt(5)) / 2 def fib_approx(n): return (phi**n - phi2**n) / sqrt(5) x = range(len(data)) y = [fib_approx(n) for n in x] # Now plot to compare fib_raw and y # Compare error, etc
W tym przypadku wartości samego ciągu Fibonacciego były nieistotne. Wszystko, czego potrzebowaliśmy, to rozmiar sekwencji wejściowej, z którą porównaliśmy.
źródło
Bardzo prosty przykład:
def loadById(self, id): if id in range(len(self.itemList)): self.load(self.itemList[id])
Nie przychodzi mi do głowy rozwiązanie, które nie wykorzystuje szybko kompozycji pasmowo-soczewkowej.
Ale prawdopodobnie zamiast tego należy to zrobić,
try .. except
aby pozostać pytonicznym, jak sądzę ...źródło
if id < len(self.itemList)
Aletry...except
jest lepiej, jak mówisz.Mój kod to:
s=["9"]*int(input()) for I in range(len(s)): while not set(s[I])<=set('01'):s[i]=input(i) print(bin(sum([int(x,2)for x in s]))[2:])
Jest to sumator binarny, ale nie sądzę, aby zakres len lub wnętrze można było zastąpić, aby był mniejszy / lepszy.
źródło