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?
Мой текущий подход заключается в том, чтобы буферизовать файл в массив, однако это не идеально, так как файл довольно большой.
Ответы
Ответ 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 должен создать список индексов, для которых вам потребуется выполнить специальную операцию. Затем во втором прогоне вы можете сравнить текущий индекс с вашим списком, чтобы определить, нужно ли выполнять эту специальную операцию.