Подтвердить что ты не робот

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

Вероятно, я ошибаюсь, но мне было интересно, как это сделать в 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):
    #increment the position of the iterator by 5?
    pass
  print line

Благодаря моему ограниченному опыту в python, у меня есть только одно решение, введите счетчик и другой оператор if. перерыв цикла до тех пор, пока счетчик не достигнет 5 после того, как значение exp.match(line) будет истинным.

Там должен быть лучший способ сделать это, надеюсь, тот, который не предполагает импорт другого модуля.

Спасибо заранее!

4b9b3361

Ответ 1

В Python есть фантастический пакет под названием itertools.

Но прежде чем я это получу, это послужит хорошим объяснением того, как итерационный протокол реализован в Python. Когда вы хотите предоставить итерацию по вашему контейнеру, вы указываете метод класса __iter__(), который предоставляет тип итератора. "Понимание Python" для "утверждения" - хорошая статья, в которой описывается, как оператор for-in действительно работает на Python и дает хороший обзор того, как итераторы работают.

Посмотрите на следующее:

>>> sequence = [1, 2, 3, 4, 5]
>>> iterator = sequence.__iter__()
>>> iterator.next()
1
>>> iterator.next()
2
>>> for number in iterator:
    print number 
3
4
5

Теперь вернемся к itertools. Пакет содержит функции для различных целей итерации. Если вам когда-либо понадобится выполнить специальную последовательность, это первое место, на которое нужно обратить внимание.

Внизу вы можете найти раздел Recipes, который содержит рецепты для создания расширенного набора инструментов с использованием существующих itertools в качестве строительных блоков.

И есть интересная функция, которая делает именно то, что вам нужно:

def consume(iterator, n):
    '''Advance the iterator n-steps ahead. If n is none, consume entirely.'''
    collections.deque(itertools.islice(iterator, n), maxlen=0)

Вот быстрый, читаемый пример того, как он работает (Python 2.5):

>>> import itertools, collections
>>> def consume(iterator, n):
    collections.deque(itertools.islice(iterator, n))
>>> iterator = range(1, 16).__iter__()
>>> for number in iterator:
    if (number == 5):
        # Disregard 6, 7, 8, 9 (5 doesn't get printed just as well)
        consume(iterator, 4)
    else:
        print number

1
2
3
4
10
11
12
13
14
15

Ответ 2

itertools.islice:

lines = iter(cdata.splitlines())
for line in lines:
    if exp.match(line):
       #increment the position of the iterator by 5
       for _ in itertools.islice(lines, 4):
           pass
       continue # skip 1+4 lines
    print line

Например, если exp, cdata:

exp = re.compile(r"skip5")
cdata = """
before skip
skip5
1 never see it
2 ditto
3 ..
4 ..
5 after skip
6 
"""

Тогда выход:

before skip
5 after skip
6 

Реализация на языке C примера Cython

i = 0
while i < 100:
    if i == 50:
       i += 10
    print i
    i += 1

Как @[Гленн Мейнард] указал в комментарий, если вам нужно сделать очень большие переходы, такие как я + = 100000000, тогда вы должны использовать явный while, а не просто пропустить шаги в цикле for.

Здесь пример, который использует явный цикл while вместо islice:

lines = cdata.splitlines()
i = 0
while i < len(lines):
    if exp.match(lines[i]):
       #increment the position of the iterator by 5
       i += 5
    else:
       print lines[i]
       i += 1

В этом примере создается тот же результат, что и предыдущий пример islice.

Ответ 3

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

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:
                iterator.next()
            except StopIteration:
                break
    else:
        print line

Ответ 4

Не совсем уверен, что я следую вашему мыслительному процессу, но здесь есть кое-что, чтобы питаться.

for i in range(len(cdata.split('\n'))):
  if i in range(50,60): continue
  line = cdata[i]
  if exp.match(line):
    #increment the position of the iterator by 5?
    pass
  print line

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

Ответ 5

Вы можете сбросить значения из итератора

def dropvalues(iterator, vals):
    for i in xrange(vals): iterator.next()

Теперь просто убедитесь, что у вас есть объект итератора для работы с lines = iter(cdata.split('\n')); и переверните его.

Ответ 6

Возможно, с genexps. Не очень, но...

Что-то вроде этого:

>>> gx = (line for line in '1 2 x 3 4 5 6 7 x 9 10 11 12 x 1'.split('\n'))
>>> for line in gx:
...   if line == 'x':
...      for i in range(2):
...          line = gx.next()
...   print line

Единственная проблема - гарантировать, что gx может быть следующим() - ed. Вышеприведенный пример специально генерирует исключение из-за последнего x.

Ответ 7

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

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

Ответ 8

Я не могу разобрать вопрос, который хорошо меняется, потому что есть этот блок запутанного и нерелевантного кода C. Удалите его.

Фокусировка только на коде Python и на вопросе о том, как пропустить 5 строк...

lineIter= iter( cdata.splitlines() )
for line in lineIter:
  if exp.match(line):
    for count in range(5):
        line = lineIter.next()
  print line