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

Python for-loop look-ahead

У меня есть цикл python for, в котором мне нужно просмотреть один элемент, чтобы увидеть, нужно ли выполнять действие перед обработкой.

for line in file:
    if the start of the next line == "0":
        perform pre-processing
        ...
    continue with normal processing
    ...

Есть ли простой способ сделать это в python? Мой текущий подход заключается в том, чтобы буферизовать файл в массив, однако это не идеально, так как файл довольно большой.

4b9b3361

Ответ 1

вы можете получить любую итерабельность для предварительной выборки следующего элемента с помощью этого рецепта:

from itertools import tee, islice, izip_longest
def get_next(some_iterable, window=1):
    items, nexts = tee(some_iterable, 2)
    nexts = islice(nexts, window, None)
    return izip_longest(items, nexts)

Пример использования:

for line, next_line in get_next(myfile):
    if next_line and next_line.startswith("0"):
        ... do stuff

Код позволяет вам передать параметр window как большее значение, если вы хотите посмотреть 2 или более строк вперед.

Ответ 2

У вас может быть prev_line, где вы сохраняете предыдущую строку и обрабатываете ее, когда вы читаете строку только с учетом вашего состояния.

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

prev_line = None
for line in file:
    if prev_line is not None and the start of the next line == "0":
        perform pre-processing on prev_line
        ...
    continue with normal processing
    ...
    prev_line = line

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

Ответ 3

По строкам ответа nosklo я склонен использовать следующий шаблон:

Функция pairwise из превосходного рецептов itertools идеально подходит для этого:

from itertools import tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Используя его в вашем коде, мы получаем:

for line, next_line in pairwise(file):
    if next_line.startswith("0"):
        pass #perform pre-processing
        #...
    pass #continue with normal processing

Как правило, для этого типа обработки (lookahead in iterable) я склонен использовать функцию окна . Pairwise - частный случай окна размером 2.

Ответ 4

Вам просто нужно буферизировать одну строку.

for line in file:
  if (prevLine is not None):
    //test line as look ahead and then act on prevLine
  prevLine = line

Ответ 5

Это тоже должно работать. Я всегда предпочитаю называть next по настройке something = None для первого раунда.

prev_line = next(the_file)
for current_line in the_file:
    if current_line.startswith('0'):
        do_stuff( prev_line )
    # continue with normal processing
    # ...
    prev_line = current_line

Ответ 6

more_itertools имеет несколько поисковых инструментов. Здесь мы продемонстрируем некоторые инструменты и абстрактную функцию для обработки строк файла. Дано:

f = """\
A
B
C
0
D\
"""
lines = f.splitlines()

код

import more_itertools as mit


def iter_lookahead(iterable, pred):
    # Option 1
    p = mit.peekable(iterable)
    try:
        while True:
            line = next(p)
            next_line = p.peek()
            if pred(next_line):
                # Do something
                pass
            else:
                print(line)
    except StopIteration:
        return


pred = lambda x: x.startswith("0")
iter_lookahead(lines, pred)

Выход

A
B
0

Вот другие варианты, использующие ту же библиотеку, которая включает инструменты pairwise и windowed, упомянутые @Muhammad Alkarouri.

# Option 2
for line, next_line in mit.pairwise(lines):
    if pred(next_line):            
        # Do something
        pass
    else:
        print(line)

# Option 3
for line, next_line in mit.windowed(lines, 2):
    if pred(next_line):            
        # Do something
        pass
    else:
        print(line)

Последние параметры могут запускаться независимо или заменять логику в предыдущей функции.

Ответ 7

Я не эксперт Python, но я бы предположил, что для этого вам нужно использовать 2 цикла. Первый прогон цикла for должен создать список индексов, для которых вам потребуется выполнить специальную операцию. Затем во втором прогоне вы можете сравнить текущий индекс с вашим списком, чтобы определить, нужно ли выполнять эту специальную операцию.