Итерация по файлу с чтением первых N значений

1

Я читаю 3 строки за раз из файла с номерами 1,2,3... 100

Я хочу, чтобы результат выглядел примерно так. 1 2 3 2 3 4 3 4 5

Однако со следующим кодом он печатает непрерывные номера

with open("/home/osboxes/num", "r+") as f:
for line in f:
    print(line)
    line2 = f.__next__()
    print(line2)
    line3 = f.__next__()
    print(line3)

Есть ли способ вернуться к итерации и пропустить строку файла и отобразить вывод, как показано выше

Теги:
file
python-3.x
loops
iteration

3 ответа

1
Лучший ответ

Предположим, что вместо вашего файлового объекта у нас есть итератор типа iter(range(100)), чтобы произвести наш ожидаемый результат, используя next вы можете копировать итератор с помощью itertools.tee столько раз, сколько хотите, и создать zip из своего итераторы на основе ожидаемого результата:

In [3]: r = iter(range(100))

In [4]: from itertools import tee

In [5]: r, n, m = tee(r, 3)  # copy the iterator 3 times 

In [6]: next(n)  # consume the first item of n
Out[6]: 0

In [7]: next(m);next(m)  # consume the first 2 items of m
Out[7]: 1

In [8]: list(zip(r, n, m))

#Out[8]: 
#[(0, 1, 2),
# (1, 2, 3),
# (2, 3, 4),
# (3, 4, 5),
# (4, 5, 6),
# (5, 6, 7),
# ...

Теперь вы можете сделать то же самое с файлом:

from itertools import tee

with open("/home/osboxes/num", "r+") as f:
    f, n, m = tee(f, 3)
    next(n);next(m);next(m)
    for i, j , k in zip(r, n, m):
        print(i, j, k)  # or do something else with i,j,k
  • 1
    Спасибо Касрамвд. Это работает как шарм :)
1

Если это меньший файл, как вы упомянули, вы можете использовать следующий код, но если он намного больше, чем предпочитает метод seek():

with open("abc.txt", "r+") as f:
    data = f.readlines()
    for i in range(2, len(data)):
        print("%s %s %s" % (data[i-2].rstrip(), data[i-1].rstrip(), data[i].rstrip()), end = " ")

Выход:

1 2 3 2 3 4 3 4 5 
  • 0
    Кажется правильным, но таким неэффективным.
  • 0
    Спасибо Камаль за ваш вклад
1

Если сохранение всего файла в переменной не является проблемой, простым решением будет:

with open("num", "r+") as f:
    lines = f.read().splitlines()
    for i in range(len(lines) - 2):
        print(lines[i])
        print(lines[i + 1])
        print(lines[i + 2])

Для более эффективного решения см. Решение @Kasramvd с использованием итераторов.

В качестве альтернативы без итераторов вы можете сохранить последние 2 значения:

with open("num", "r+") as f:
    prev1, prev2 = None, None
    for line in f:
        if prev1 is not None and prev2 is not None:
            print(prev1)
            print(prev2)
            print(line)
        prev1, prev2 = prev2, line
  • 0
    Кажется правильным, но таким неэффективным.
  • 0
    Иногда производительность менее важна, чем возможность сопровождения кода (мне нравится ваше решение, но разработчики потратят больше времени на его понимание). Как я уже сказал, это зависит от размера ввода.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню