Пропустить несколько итераций в цикле

У меня есть список в цикле, и я хочу пропустить 3 элемента после достижения look. В этот ответ было сделано несколько предложений, но я не смог их правильно использовать:

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

Четыре раза continue это, конечно, нонсенс, а использование четырех раз next() не работает.

Вывод должен выглядеть так:

always
look
aside
of
life

person Mehdi Nellen    schedule 10.03.2014    source источник


Ответы (7)


for использует iter(song) для цикла; вы можете сделать это в своем собственном коде, а затем продвигать итератор внутри цикла; повторный вызов iter() для итерации вернет только тот же итерируемый объект, поэтому вы можете продвигать итерацию внутри цикла, а for следует прямо на следующей итерации.

Усовершенствуйте итератор с помощью next()функции; он правильно работает как в Python 2, так и в 3 без необходимости корректировать синтаксис:

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)

Перемещая строку print sing вверх, мы также можем избежать повторения самих себя.

Использование next() таким образом может вызвать исключение StopIteration, если в итерируемом объекте нет значений.

Вы могли бы поймать это исключение, но было бы проще дать next() второй аргумент, значение по умолчанию, чтобы игнорировать исключение и вместо этого возвращать значение по умолчанию:

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, '')

Вместо этого я бы использовал itertools.islice(), чтобы пропустить 3 элемента; сохраняет повторные next() вызовы:

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), '')

Итерируемый islice(song_iter, 3, 4) пропустит 3 элемента, затем вернет 4-й, а затем будет готов. Таким образом, вызов next() для этого объекта извлекает 4-й элемент из song_iter().

Демо:

>>> 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
person Martijn Pieters    schedule 10.03.2014

Я думаю, здесь можно использовать итераторы и next:

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

или с обработкой исключений (которая короче и надежнее, как заметил @Steinar):

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
person bereal    schedule 10.03.2014
comment
Это работает для представленного случая, но имейте в виду, что любой элемент, который оценивается как False, нарушит это решение (например, ['always', 'look', '', 'the'] или ['always', 'look', None, 'the']). - person Steinar Lima; 10.03.2014

Вы можете сделать это и без iter(), просто используя дополнительную переменную:

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
person SaeX    schedule 10.03.2014
comment
Это довольно нечитаемо; действительно трудно понять, в чем здесь замысел. - person Martijn Pieters; 10.03.2014
comment
@MartijnPieters: согласился, что будут лучшие решения. Просто хотел указать на другой подход. - person SaeX; 10.03.2014

Конечно, вы можете использовать три раза в следующий раз (здесь я на самом деле делаю это четыре раза)

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

затем

always
look
aside
of
life
person hivert    schedule 10.03.2014

На самом деле, использование .next() три раза не является ерундой. Если вы хотите пропустить n значений, вызовите next() n+1 раз (не забудьте присвоить значение последнего вызова чему-либо), а затем «вызовите» continue.

Чтобы получить точную копию кода, который вы разместили:

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
person radomaj    schedule 10.03.2014

Я считаю, что следующий код является самым простым для меня.

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

Это дает результаты, которые вы ищете.

always
look
aside
of
life
person MarkTheCoder    schedule 15.07.2021

person    schedule
comment
Работает для этого конкретного искусственного примера, но не будет работать должным образом на произвольных итераторах/генераторах, где возможен переход к следующему элементу или пропуск, но выбор произвольного элемента по индексу либо невозможен (если они не сохранены), либо медленны . - person Peteris; 10.03.2014