Pomiń pierwszy wpis dla pętli w pythonie?

187

W Pythonie, jak zrobić coś takiego:

for car in cars:
   # Skip first and last, do work for rest
Rolando
źródło
4
Jestem nowicjuszem, ale używam for n, i in enumerate(cars): if n!= 0: do something to i. logika polega na tym, że dodaje „licznik” do każdej wartości, którą można następnie celować np if n == some_value. za pomocą . w tym przykładzie zrobiłby coś dla każdego wystąpienia i, z wyjątkiem pierwszego.
user1063287

Odpowiedzi:

268

Pozostałe odpowiedzi działają tylko dla sekwencji.

W przypadku dowolnej iteracji pomiń pierwszy element:

itercars = iter(cars)
next(itercars)
for car in itercars:
    # do work

Jeśli chcesz pominąć ostatni, możesz:

itercars = iter(cars)
# add 'next(itercars)' here if you also want to skip the first
prev = next(itercars)
for car in itercars:
    # do work on 'prev' not 'car'
    # at end of loop:
    prev = car
# now you can do whatever you want to do to the last one on 'prev'
agf
źródło
1
Zobacz także Sven Marnach „s odpowiedź
AGF
2
Odkryłem, że robienie cars.pop (0) i cars.pop () działa dobrze.
dreamwork801
@ dreamwork801 Moja odpowiedź i Svena, które łączę w pierwszym komentarzu, działają na wszystkie iterowalne, nawet nieskończone, ponieważ nie wymagają one operacji O (n) na danych przed rozpoczęciem iteracji. Zarówno twoja sugestia, jak i sugestia Abhjita działają tylko dla sekwencji, a nie dla żadnej iteracji.
agf
356

Aby pominąć pierwszy element w Pythonie, możesz po prostu napisać

for car in cars[1:]:
    # Do What Ever you want

lub pominąć ostatni elem

for car in cars[:-1]:
    # Do What Ever you want

Możesz użyć tej koncepcji do dowolnej sekwencji.

Abhijit
źródło
52
Nie dla wszystkich iterowalnych , ale dla wszystkich sekwencji .
Sven Marnach,
2
Co powiesz na wykorzystanie pamięci? Czy wycinek tworzy nową kopię podsekwencji?
Voyager,
@ Voyager Tak, tworzy nową kopię.
Srinivas Reddy Thatiparthy
27

Najlepszym sposobem na pominięcie pierwszych elementów jest:

from itertools import islice
for car in islice(cars, 1, None):
    # do something

islice w tym przypadku jest wywoływane z punktem początkowym 1 i punktem końcowym Brak, co oznacza koniec iteratora.

Aby móc pominąć elementy z końca iteracji, musisz znać jego długość (zawsze jest to możliwe dla listy, ale niekoniecznie dla wszystkiego, co możesz iterować). na przykład islice (samochody, 1, len (samochody) -1) pomija pierwszy i ostatni element na liście samochodów.

Roee Shenberg
źródło
Spójrz na odpowiedź Svena (niedoceniona). Obejmuje pomijanie dowolnej liczby elementów na początku i / lub końcu dowolnej iteracji przy użyciu islicecałkiem dobrze, bez znajomości długości lub przechowywania większej liczby przedmiotów na raz, niż jest to absolutnie konieczne.
agf
Odpowiedź Svena zapisze w rzeczywistości cały iterator w pamięci - kolekcje.deque przejdą przez iterator. Spróbuj zrobić coś takiego jak collections.deque (xrange (10000000)). Nie musisz przechowywać wszystkich danych w pamięci, jeśli chcesz pominąć pierwszy element ...
Roee Shenberg
2
isliceJest to, co jest przekazywane do deque, a nie całego iterator, i to tylko długość liczby elementów, aby przejść na koniec. Nie przechowuje całego iteratora w pamięci.
agf
26

Oto bardziej ogólna funkcja generatora, która pomija dowolną liczbę elementów od początku i końca iteracji:

def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()

Przykładowe użycie:

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]
Sven Marnach
źródło
Może chcesz dodać szybką ścieżkę at_end == 0.
agf
collections.deque (...) natychmiast przejdzie przez iterator. Oznacza to, że pominięcie (xrange (10000000), 1) zajmie dużo pamięci, chociaż tak naprawdę nie powinno.
Roee Shenberg,
4
@RoeeShenberg: skip(xrange(10000000), 1)użyje at_end=0, więc parametrem deque()będzie islice(it, 0), który będzie zużywał tylko zero elementów it. To nie zajmie dużo pamięci.
Sven Marnach,
8
for item in do_not_use_list_as_a_name[1:-1]:
    #...do whatever
KurzedMetal
źródło
3
Nie używaj listjako nazwy zmiennej
Abhijit,
OP chce tylko pominąć pierwszy element. dlaczego: -1?
luke14free
6
To nie jest właściwie zastrzeżone ; nazwa listmoże zostać ponownie powiązana. Dlatego nie powinien , raczej niż nie , użyj go.
jscs
@ luke14free pytanie brzmi: pomiń pierwszy element, ale jego komentarz do kodu sugeruje, że naprawdę chce pominąć pierwszy i ostatni.
JerseyMike,
@ luke14free to mówi tytuł, a nie to, co wpisał w kodzie: „pomiń, jeśli pierwszy lub ostatni”
KurzedMetal
3

Na podstawie odpowiedzi @ SvenaMarnacha, ale nieco prostsze i bez użycia deque

>>> def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]
>>> list(skip(range(10), at_start=2, at_end=5))
[2, 3, 4]

Również uwaga, w oparciu o mój timeitwynik, jest to nieznacznie szybsze niż rozwiązanie deque

>>> iterable=xrange(1000)
>>> stmt1="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    it = itertools.islice(it, at_start, None)
    it, it1 = itertools.tee(it)
    it1 = itertools.islice(it1, at_end, None)
    return (next(it) for _ in it1)
list(skip(iterable,2,2))
    """
>>> stmt2="""
def skip(iterable, at_start=0, at_end=0):
    it = iter(iterable)
    for x in itertools.islice(it, at_start):
        pass
    queue = collections.deque(itertools.islice(it, at_end))
    for x in it:
        queue.append(x)
        yield queue.popleft()
list(skip(iterable,2,2))
        """
>>> timeit.timeit(stmt = stmt1, setup='from __main__ import iterable, skip, itertools', number = 10000)
2.0313770640908047
>>> timeit.timeit(stmt = stmt2, setup='from __main__ import iterable, skip, itertools, collections', number = 10000)
2.9903135454296716
Abhijit
źródło
Korzystając z niego tee(), nadal tworzysz całą listę pamięci generatora, prawda? (twój it1)
Jabberwockey
3

Przykład:

mylist=['one'.'two','three'.'four'.'five']
for i in mylist[1:]:
   print(i)

W indeksie pythonowym zaczynającym się od 0, możemy używać operatora krojenia, aby manipulować iteracją.

for i in range(1,-1):
Tono Kuriakose
źródło
2

Cóż, twoja składnia nie jest tak naprawdę Pythonem.

Iteracje w Pythonie są ponad zawartością kontenerów (cóż, technicznie jest to ponad iteratorami), ze składnią for item in container. W tym przypadku kontener jest carslistą, ale chcesz pominąć pierwszy i ostatni element, co oznacza cars[1:-1](listy python są liczone od zera, liczby ujemne liczą się od końca i :kroi składnię.

Więc chcesz

for c in cars[1:-1]:
    do something with c
Andrew Jaffe
źródło
4
To nie będzie działać z iterowalnym (np. Generatorem), tylko z sekwencją.
Roee Shenberg,
2

Alternatywna metoda:

for idx, car in enumerate(cars):
    # Skip first line.
    if not idx:
        continue
    # Skip last line.
    if idx + 1 == len(cars):
        continue
    # Real code here.
    print car
Banan
źródło
2

Oto mój preferowany wybór. Nie wymaga dodawania wiele do pętli i używa tylko wbudowanych narzędzi.

Przejdź od:

for item in my_items:
  do_something(item)

do:

for i, item in enumerate(my_items):
  if i == 0:
    continue
  do_something(item)
na komputerze
źródło
1

Jeśli carsjest to sekwencja, którą możesz po prostu zrobić

for car in cars[1:-1]:
    pass
Praveen Gollakota
źródło
1

The more_itertoolsProjekt rozszerzaitertools.islice obsłużyć ujemnych indeksów.

Przykład

import more_itertools as mit

iterable = 'ABCDEFGH'
list(mit.islice_extended(iterable, 1, -1))
# Out: ['B', 'C', 'D', 'E', 'F', 'G']

Dlatego możesz elegancko zastosować elementy do wycinania między pierwszym a ostatnim elementem iteracji:

for car in mit.islice_extended(cars, 1, -1):
    # do something
pylang
źródło
0

Robię to w ten sposób, mimo że wygląda to na hack, działa za każdym razem:

ls_of_things = ['apple', 'car', 'truck', 'bike', 'banana']
first = 0
last = len(ls_of_things)
for items in ls_of_things:
    if first == 0
        first = first + 1
        pass
    elif first == last - 1:
        break
    else:
        do_stuff
        first = first + 1
        pass
dmb
źródło