Ignorer la première entrée de la boucle for en python?

187

En python, comment faire quelque chose comme:

for car in cars:
   # Skip first and last, do work for rest
Rolando
la source
4
je suis un débutant, mais j'utilise for n, i in enumerate(cars): if n!= 0: do something to i. la logique est qu'il ajoute un «compteur» à chaque valeur que vous pouvez ensuite cibler par exemple avec if n == some_value. dans cet exemple, il ferait quelque chose pour chaque instance de i, sauf pour la première.
user1063287

Réponses:

268

Les autres réponses ne fonctionnent que pour une séquence.

Pour tout itérable, pour ignorer le premier élément:

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

Si vous voulez sauter le dernier, vous pouvez faire:

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
la source
1
Voir aussi la réponse de Sven Marnach
2013
2
J'ai trouvé que faire cars.pop (0) et cars.pop () fonctionnait bien.
dreamwork801
@ dreamwork801 Ma réponse et celle de Sven, que je lie dans le premier commentaire, fonctionnent pour toutes les itérables, même infinies, car elles ne nécessitent pas d'opération O (n) sur les données avant le début de l'itération. Votre suggestion, et celle d'Abhjit, ne fonctionnent que pour les séquences, pas pour les itérations.
agf
356

Pour ignorer le premier élément en Python, vous pouvez simplement écrire

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

ou pour sauter le dernier élément

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

Vous pouvez utiliser ce concept pour n'importe quelle séquence.

Abhijit
la source
52
Pas pour tous les itérables , mais pour toutes les séquences .
Sven Marnach
2
Qu'en est-il de l'utilisation de la mémoire? Slice fait-il une nouvelle copie de la sous-séquence?
Voyager
@Voyager Oui, il fait une nouvelle copie.
Srinivas Reddy Thatiparthy
27

La meilleure façon d'ignorer le ou les premiers éléments est:

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

islice dans ce cas est invoqué avec un point de départ de 1 et un point de fin de None, signifiant la fin de l'itérateur.

Pour pouvoir sauter des éléments à partir de la fin d'un itérable, vous devez connaître sa longueur (toujours possible pour une liste, mais pas nécessairement pour tout ce sur quoi vous pouvez itérer). par exemple, islice (cars, 1, len (cars) -1) ignorera les premier et dernier éléments de la liste des voitures.

Roee Shenberg
la source
Jetez un œil à la réponse (sous-estimée) de Sven. Il couvre isliceassez bien sauter un nombre arbitraire d'éléments au début et / ou à la fin de tout itérable , sans connaître la longueur ni stocker plus d'éléments en mémoire à la fois que ce qui est absolument nécessaire.
agf
La réponse de Sven stockera en fait l'itérateur entier en mémoire - collections.deque passera par l'itérateur. Essayez de faire quelque chose comme collections.deque (xrange (10000000)). Il n'est pas nécessaire de stocker tous les entiers en mémoire si vous souhaitez ignorer le premier élément ...
Roee Shenberg
2
An isliceest ce qui est passé à l' dequeitérateur, pas à l'itérateur entier, et c'est seulement la longueur du nombre d'éléments à sauter à la fin. Il ne stocke pas l'itérateur entier en mémoire.
agf
26

Voici une fonction de générateur plus générale qui saute n'importe quel nombre d'éléments du début et de la fin d'un itérable:

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

Exemple d'utilisation:

>>> list(skip(range(10), at_start=2, at_end=2))
[2, 3, 4, 5, 6, 7]
Sven Marnach
la source
Pourrait vouloir ajouter un chemin rapide pour at_end == 0.
agf
collections.deque (...) passera immédiatement par l'itérateur. Cela signifie que skip (xrange (10000000), 1) prendra beaucoup de mémoire même si cela ne devrait vraiment pas.
Roee Shenberg
4
@RoeeShenberg: skip(xrange(10000000), 1)utilisera at_end=0, donc le paramètre à deque()sera islice(it, 0), qui ne consommera que zéro élément de it. Cela ne prendra pas beaucoup de mémoire.
Sven Marnach
8
for item in do_not_use_list_as_a_name[1:-1]:
    #...do whatever
KurzedMétal
la source
3
Ne pas utiliser listcomme nom de variable
Abhijit
l'OP veut seulement sauter le premier élément. pourquoi: -1?
luke14 gratuit le
6
Ce n'est pas vraiment réservé ; le nom listpeut être lié de nouveau. C'est pourquoi vous ne devriez pas , plutôt que ne pouvez pas , l'utiliser.
jscs
@ luke14free, la question dit ignorer le premier élément, mais son commentaire de code implique qu'il veut vraiment sauter le premier et le dernier.
JerseyMike
@ luke14free c'est ce que dit le titre, pas ce qu'il a tapé à l'intérieur du code: "sauter si le premier ou le dernier"
KurzedMetal
4

Exemple:

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

Dans l'index python à partir de 0, nous pouvons utiliser l'opérateur de découpage pour effectuer des manipulations en itération.

for i in range(1,-1):
Tono Kuriakose
la source
3

Basé sur la réponse de @SvenMarnach, mais un peu plus simple et sans utiliser 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]

Notez également, sur la base de mon timeitrésultat, c'est légèrement plus rapide que la solution 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
la source
En utilisant tee(), vous créez toujours une liste entière en mémoire pour le générateur, non? (votre it1)
Jabberwockey
2

Eh bien, votre syntaxe n'est pas vraiment Python pour commencer.

Les itérations en Python sont sur le contenu des conteneurs (enfin, techniquement, c'est sur les itérateurs), avec une syntaxe for item in container. Dans ce cas, le conteneur est la carsliste, mais vous voulez ignorer le premier et le dernier éléments, ce qui signifie que cars[1:-1](les listes python sont de base zéro, les nombres négatifs comptent à partir de la fin et :tranchent la syntaxe.

Alors tu veux

for c in cars[1:-1]:
    do something with c
Andrew Jaffe
la source
4
Cela ne fonctionnera pas avec un itérable (par exemple un générateur), uniquement avec une séquence.
Roee Shenberg
2

Une méthode alternative:

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
banane
la source
2

Voici mon choix préféré. Il ne nécessite pas beaucoup d'ajout à la boucle et n'utilise que des outils intégrés.

Aller de:

for item in my_items:
  do_something(item)

à:

for i, item in enumerate(my_items):
  if i == 0:
    continue
  do_something(item)
ordinateur portable
la source
1

Si carsc'est une séquence que vous pouvez simplement faire

for car in cars[1:-1]:
    pass
Praveen Gollakota
la source
1

Le more_itertoolsprojet s'étend itertools.islicepour gérer les indices négatifs.

Exemple

import more_itertools as mit

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

Par conséquent, vous pouvez l'appliquer élégamment en tranches entre le premier et le dernier élément d'un itérable:

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

Je le fais comme ça, même si ça ressemble à un hack ça marche à chaque fois:

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
la source