0

Python: произвольное увеличение итератора внутри цикла

10

Я, вероятно, подхожу к этому вопросу неправильно, но мне интересно, как это можно реализовать на Python.

Сначала вот пример кода на C:

int i;

for(i=0;i<100;i++){
  if(i == 50)
    i = i + 10;
  printf("%i\n", i);
}

Как вы можете заметить, число 50 в выводе никогда не появляется.

Теперь мой вопрос: как реализовать что-то подобное на Python? Например:

for line in cdata.split('\n'):
  if exp.match(line):
    # увеличить позицию итератора на 5?
    pass
  print(line)

Учитывая мой ограниченный опыт в Python, у меня есть лишь одно решение: ввести счётчик и добавить ещё одно условие if. Остановить цикл, пока счётчик не достигнет 5, после того как условие exp.match(line) будет истинным.

Должен же быть лучший способ это сделать, желательно без импорта дополнительных модулей.

Заранее спасибо!

5 ответ(ов)

0

Если вы работаете с числами, то списковое выражение может помочь:

for i in [x for x in range(0, 99) if x < 50 and x > 59]:
    print(i)

Однако, если нужно перемещать итератор вперед, это может быть несколько сложнее. Я бы предложил заранее подготовить список, если вы не хотите использовать подход с счетчиком. Например, вы можете разбить cdata, определить индексы строки, которая соответствует вашему условию, а затем удалить эту строку и последующие. В противном случае, вам останется подход со счетчиком, который, честно говоря, не так уж неприятен, как вы его описываете.

Еще один вариант решения этой задачи:

iterator = iter(cdata.split('\n'))
for line in iterator:
    if exp.match(line):
        for i in range(0, 5):
            try:
                next(iterator)
            except StopIteration:
                break
    else:
        print(line)

Этот код создает итератор из строк cdata, и если строка соответствует вашему регулярному выражению, он пропускает следующие пять строк. В противном случае, просто выводит текущую строку.

0

Не совсем понимаю вашу мысль, но вот что-то, на чем можно поразмыслить...

for i in range(len(cdata.split('\n'))):
    if i in range(50, 60): 
        continue
    line = cdata[i]
    if exp.match(line):
        # увеличить позицию итератора на 5?
        pass
    print(line)

Не уверен, что именно вы хотите сделать, но использование range(len(..)) должно помочь вам.

0

В ответ на ваш вопрос, вот как можно реализовать функцию для пропуска значений из итератора:

def dropvalues(iterator, vals):
    for _ in range(vals):
        next(iterator)

Убедитесь, что у вас есть объект итератора, с которым вы собираетесь работать. Для этого вы можете создать итератор из строки, разбивая её по символу новой строки:

lines = iter(cdata.split('\n'))

Затем вы можете использовать dropvalues, чтобы пропустить нужные значения. Например:

dropvalues(lines, 3)  # Это пропустит первые 3 строки итератора
for line in lines:
    print(line)  # Будет выводить строки, начиная с четвертой

Не забудьте, что функция next в Python 3 заменяет iterator.next() из Python 2.

0

Чтобы реализовать такую задачу, можно воспользоваться генераторами, но вам нужно учитывать, что в Python 3 метод next() вызывается не как gx.next(), а с помощью функции next(gx). Также стоит позаботиться о том, чтобы обрабатывать ситуацию, когда генератор достигнет конца, чтобы избежать исключений.

Вот пример того, как это можно сделать:

gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split())

try:
    while True:
        line = next(gx)
        if line == 'x':
            # Пропускаем следующие два элемента, если это возможно
            for i in range(2):
                line = next(gx)
        print(line)
except StopIteration:
    pass  # Игнорируем исключение, когда генератор заканчивается

В этом коде мы используем бесконечный цикл while True, чтобы продолжать итерацию по генератору, пока не достигнем конца. Когда встречаем символ 'x', мы пропускаем следующие два элемента, используя next(gx). Команда StopIteration обрабатывается с помощью блока try-except, чтобы избежать выброса исключения в случае, если элементы закончились.

Таким образом, вы избежите ошибки с последним 'x' и получите нужный результат.

0

Для вашего примера, поскольку вы работаете со списками (индексируемыми последовательностями), а не с итераторами, я бы порекомендовал следующее:

lines = cdata.split("\n")
for line in lines[:50] + lines[60:]:
    print(line)

Это не самый эффективный способ, так как потенциально создаются 3 новых списка (но если пропускаемая часть больше обрабатываемой, это может оказаться более эффективным, чем другие варианты), но код выглядит довольно чисто и понятно.

Если вам не жалко использовать модуль itertools, можете легко преобразовать списки в последовательности:

from itertools import chain, islice
for line in chain(islice(lines, None, 50), islice(lines, 60, None)):
    print(line)

В этом случае код становится более оптимизированным, и вы избежите создания лишних списков.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь