Salta la prima voce per loop in Python?


187

In Python, come posso fare qualcosa del tipo:

for car in cars:
   # Skip first and last, do work for rest

4
Sono un principiante, ma lo sto usando for n, i in enumerate(cars): if n!= 0: do something to i. la logica è che aggiunge un "contatore" a ciascun valore che può essere scelto come target, ad es if n == some_value. in questo esempio farebbe qualcosa per ogni istanza di i, tranne per il primo.
user1063287

Risposte:


268

Le altre risposte funzionano solo per una sequenza.

Per ogni iterabile, per saltare il primo elemento:

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

Se vuoi saltare l'ultimo, puoi fare:

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'

1
Vedere anche Sven Marnach 's risposta
AGF

2
Ho scoperto che fare cars.pop (0) e cars.pop () funziona bene.
dreamwork801,

@ dreamwork801 La mia risposta e quella di Sven, che collego nel primo commento, funzionano per qualsiasi iterabile, anche infinito, in quanto non richiedono un'operazione O (n) sui dati prima dell'inizio dell'iterazione. Il tuo suggerimento, e quello di Abhjit, funzionano entrambi solo per le sequenze, non tutte ripetibili.
agf

356

Per saltare il primo elemento in Python puoi semplicemente scrivere

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

o per saltare l'ultimo elem

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

Puoi usare questo concetto per qualsiasi sequenza.


52
Non per tutti gli iterabili , ma per tutte le sequenze .
Sven Marnach,

2
Che ne dici dell'utilizzo della memoria? Slice crea una nuova copia della sottosequenza?
Voyager,

@Voyager Sì, crea una nuova copia.
Srinivas Reddy Thatiparthy,

27

Il modo migliore per saltare i primi elementi è:

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

islice in questo caso viene invocato con un punto iniziale di 1 e un punto finale di Nessuno, che indica la fine dell'iteratore.

Per saltare gli elementi dalla fine di un iterabile, devi conoscerne la lunghezza (sempre possibile per un elenco, ma non necessariamente per tutto ciò su cui puoi iterare). ad esempio, islice (auto, 1, len (auto) -1) salterà il primo e l'ultimo elemento nell'elenco auto.


Dai un'occhiata alla risposta (non apprezzata) di Sven. Copre saltando un numero arbitrario di elementi all'inizio e / o alla fine di qualsiasi iterabile usando isliceabbastanza bene, senza conoscere la lunghezza o memorizzare più elementi contemporaneamente in memoria di quanto assolutamente necessario.
AGF

La risposta di Sven in realtà memorizzerà l'intero iteratore in memoria - collections.deque scorrerà attraverso l'iteratore. Prova a fare qualcosa di simile a collections.deque (xrange (10000000)). Non è necessario archiviare tutti gli interi in memoria se si desidera saltare il primo elemento ...
Roee Shenberg,

2
An isliceè ciò che viene passato a deque, non l'intero iteratore, ed è solo la lunghezza del numero di elementi da saltare alla fine. Non memorizza l'intero iteratore in memoria.
agf

26

Ecco una funzione del generatore più generale che salta un numero qualsiasi di elementi dall'inizio e dalla fine di un iterabile:

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

Esempio di utilizzo:

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

Potrebbe voler aggiungere un percorso rapido per at_end == 0.
AGF

collections.deque (...) passerà immediatamente attraverso l'iteratore. Ciò significa che skip (xrange (10000000), 1) occuperà molta memoria anche se in realtà non dovrebbe.
Roee Shenberg,

4
@RoeeShenberg: skip(xrange(10000000), 1)userà at_end=0, quindi il parametro deque()sarà islice(it, 0), che consumano solo zero elementi di it. Questo non richiederà molta memoria.
Sven Marnach,

8
for item in do_not_use_list_as_a_name[1:-1]:
    #...do whatever

3
Non utilizzare listcome nome variabile
Abhijit

l'OP vuole solo saltare il primo elemento. perché: -1?
luke14free

6
In realtà non è riservato ; il nome listpuò essere rilegato. Ecco perché non dovresti , piuttosto che non puoi , usarlo.
jscs,

@ luke14free, la domanda dice saltare il primo elemento, ma il suo commento in codice implica che vuole davvero saltare il primo e l'ultimo.
JerseyMike,

@ luke14free è quello che dice il titolo, non quello che ha scritto nel codice: "salta se primo o ultimo"
KurzedMetal

3

Basato sulla risposta di @SvenMarnach, ma un po 'più semplice e senza usare 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]

Inoltre, in base al mio timeitrisultato, questo è leggermente più veloce della soluzione di 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

Usando tee(), stai ancora creando un intero elenco in memoria per il generatore, giusto? (tuo it1)
Jabberwockey

3

Esempio:

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

Nell'indice python a partire da 0, possiamo usare l'operatore slicing per effettuare manipolazioni nell'iterazione.

for i in range(1,-1):

2

Bene, la tua sintassi non è proprio Python per cominciare.

Le iterazioni in Python sono sul contenuto dei container (beh, tecnicamente è su iteratori), con una sintassi for item in container. In questo caso, il contenitore è l' carselenco, ma si desidera saltare il primo e l'ultimo elemento, quindi ciò significa cars[1:-1](gli elenchi di Python sono basati su zero, i numeri negativi contano dalla fine e: sta tagliando la sintassi.

Quindi tu vuoi

for c in cars[1:-1]:
    do something with c

4
Questo non funzionerà con un iterabile (ad es. Un generatore), solo con una sequenza.
Roee Shenberg,

2

Un metodo alternativo:

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

2

Ecco la mia scelta preferita. Non richiede di aggiungere molto al loop e non usa altro che strumenti integrati.

Andare da:

for item in my_items:
  do_something(item)

per:

for i, item in enumerate(my_items):
  if i == 0:
    continue
  do_something(item)


1

Il more_itertoolsprogetto si estendeitertools.islice per gestire indici negativi.

Esempio

import more_itertools as mit

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

Pertanto, è possibile applicare elegantemente gli elementi di divisione tra il primo e l'ultimo elemento di un iterabile:

for car in mit.islice_extended(cars, 1, -1):
    # do something

0

Lo faccio in questo modo, anche se sembra un hack funziona sempre:

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.