Skip multiple iterations in loop
Asked Answered
C

7

57

I have a list in a loop and I want to skip 3 elements after look has been reached. In this answer a couple of suggestions were made but I fail to make good use of them:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
for sing in song:
    if sing == 'look':
        print sing
        continue
        continue
        continue
        continue
        print 'a' + sing
    print sing

Four times continue is nonsense of course and using four times next() doesn't work.

The output should look like:

always
look
aside
of
life
Clasping answered 10/3, 2014 at 9:5 Comment(0)
G
73

for uses iter(song) to loop; you can do this in your own code and then advance the iterator inside the loop; calling iter() on the iterable again will only return the same iterable object so you can advance the iterable inside the loop with for following right along in the next iteration.

Advance the iterator with the next() function; it works correctly in both Python 2 and 3 without having to adjust syntax:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)
for sing in song_iter:
    print sing
    if sing == 'look':
        next(song_iter)
        next(song_iter)
        next(song_iter)
        print 'a' + next(song_iter)

By moving the print sing line up we can avoid repeating ourselves too.

Using next() this way can raise a StopIteration exception, if the iterable is out of values.

You could catch that exception, but it'd be easier to give next() a second argument, a default value to ignore the exception and return the default instead:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)
for sing in song_iter:
    print sing
    if sing == 'look':
        next(song_iter, None)
        next(song_iter, None)
        next(song_iter, None)
        print 'a' + next(song_iter, '')

I'd use itertools.islice() to skip 3 elements instead; saves repeated next() calls:

from itertools import islice

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
song_iter = iter(song)
for sing in song_iter:
    print sing
    if sing == 'look':
        print 'a' + next(islice(song_iter, 3, 4), '')

The islice(song_iter, 3, 4) iterable will skip 3 elements, then return the 4th, then be done. Calling next() on that object thus retrieves the 4th element from song_iter().

Demo:

>>> from itertools import islice
>>> song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
>>> song_iter = iter(song)
>>> for sing in song_iter:
...     print sing
...     if sing == 'look':
...         print 'a' + next(islice(song_iter, 3, 4), '')
... 
always
look
aside
of
life
Geriatrician answered 10/3, 2014 at 9:14 Comment(0)
K
10
>>> song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
>>> count = 0
>>> while count < (len(song)):
    if song[count] == "look" :
        print song[count]
        count += 4
        song[count] = 'a' + song[count]
        continue
    print song[count]
    count += 1

Output:

always
look
aside
of
life
Kentigerma answered 10/3, 2014 at 9:33 Comment(1)
Works for that specific artificial example, but wouldn't work appropriately on arbitrary iterators/generators, where going to the next element or skipping is possible, but fetching an arbitrary element by index is either impossible (if they aren't stored) or slow.Dyak
I
4

I think, it's just fine to use iterators and next here:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
it = iter(song)
while True:
    word = next(it, None)
    if not word:
       break
    print word
    if word == 'look':
        for _ in range(4): # skip 3 and take 4th
            word = next(it, None)
        if word:
            print 'a' + word

or, with exception handling (which is shorter as well as more robust as @Steinar noticed):

it = iter(song)
while True:
    try:
        word = next(it)
        print word
        if word == 'look':
            for _ in range(4):
                word = next(it)
            print 'a' + word 
    except StopIteration:
        break
Interrogatory answered 10/3, 2014 at 9:12 Comment(1)
This works for the case presented, but be aware that any item which evaluates to False will break this solution (e.g ['always', 'look', '', 'the'] or ['always', 'look', None, 'the'])Bazan
M
3

You can do this without an iter() as well simply using an extra variable:

skipcount = -1
song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
for sing in song:
    if sing == 'look' and skipcount <= 0:
        print sing
        skipcount = 3
    elif skipcount > 0:
        skipcount = skipcount - 1
        continue
    elif skipcount == 0:
        print 'a' + sing
        skipcount = skipcount - 1
    else:
        print sing
        skipcount = skipcount - 1
Mathewson answered 10/3, 2014 at 9:22 Comment(2)
This is rather unreadable though; it is really hard to work out what the intention is here.Geriatrician
@MartijnPieters: agreed that there will be better solutions. Just wanted to point out a different approach.Mathewson
M
2

Actually, using .next() three times is not nonsense. When you want to skip n values, call next() n+1 times (don't forget to assign the value of the last call to something) and then "call" continue.

To get an exact replica of the code you posted:

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
songiter = iter(song)
for sing in songiter:
  if sing == 'look':
    print sing
    songiter.next()
    songiter.next()
    songiter.next()
    sing = songiter.next()
    print 'a' + sing
    continue
  print sing
Manx answered 10/3, 2014 at 9:10 Comment(0)
C
2

Of course you can use three time next (here I actually do it four time)

song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']
it = iter(song)
for sing in it:
    if sing == 'look':
        print sing
        try:
           sing = it.next(); sing = it.next(); sing = it.next(); sing=it.next()
        except StopIteration:
             break
        print 'a'+sing
    else:
        print sing

Then

always
look
aside
of
life
Chavira answered 10/3, 2014 at 9:11 Comment(0)
H
0

I believe the following code is the simplest for me.

# data list
song = ['always', 'look', 'on', 'the', 'bright', 'side', 'of', 'life']

# this is one possible way
for sing in song:
    if sing != 'look'\
            and sing != 'always' \
            and sing != 'side' \
            and sing != 'of'\
            and sing != 'life':
        continue
    if sing == 'side':
        sing = f'a{sing}'  # or sing = 'aside'
    print(sing)

# this is another possible way
songs_to_keep = ['always', 'look', 'of', 'side', 'of', 'life']
songs_to_change = ['side']
for sing in song:
    if sing not in songs_to_keep:
        continue
    if sing in songs_to_change:
        sing = f'a{sing}'
    print(sing)

This produces the results you are looking for.

always
look
aside
of
life
Hartzel answered 15/7, 2021 at 2:40 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.