Я делаю симулятор виртуальной памяти, но у меня возникла проблема. Мне нужно прочитать n (8) строк из k (4) файлов, например: я читаю первые 8 строк файла 1 - файл 2 - файл 3 - файл 4, затем снова читаю строки 9 - 17 из каждого файла До тех пор, пока в каждом файле не закончатся строки.

У меня нет проблем с вводом файлов, и я уже сделал этот код.

def rr_process(quantum, file, fline):
    global rr_list #List to save the reading lines
    condition = file_len(file) #Return the total lines of passed file
    with open(file) as fp:
        line = fp.readlines() #Save all the lines of the file in a list   
        for i in range(fline,fline+quantum): #for i in range(NewStartLine, NewStartLie + n_lines)
            if i <= condition-1:
                sline = line[i].rstrip()#Remove /n from lines
                rr_list.append(sline) #append the n_lines to the list
            else:
                break 

operation = concat_count//(n_proc*quantum) #total_lines//(k_files*n_lines)

for i in range(0,operation):
    for fname in process: #Open each file (4)
         rr_process(quantum,fname,fline) #Calls the read lines function
    fline = fline + quantum + 1 #New start line number 0-9-17...

У меня вообще нет успеха, мне нужно прочитать 50 тыс. Строк, но моя программа просто читает 44446. Какая ошибка в коде? или как лучше справиться с этим? Спасибо ребята!

0
moonify 18 Апр 2019 в 18:55

2 ответа

Лучший ответ

Это можно сократить до нескольких строк кода, используя функции grouper и roundrobin, предоставленные документацией модуля itertools.

import contextlib
from itertools import zip_longest, cycle, islice, chain

# Define grouper() and roundrobin() here

with contextlib.ExitStack() as stack:
    # Open each file *once*; the exit stack will make sure they get closed
    files = [stack.enter_context(open(fname)) for frame in process]
    # Instead of iterating over each file line by line, we'll iterate
    # over them in 8-line batches.
    groups = [grouper(f, 8) for f in files]
    # Interleave the groups by taking an 8-line group from one file,
    # then another, etc.
    interleaved = roundrobin(*groups)
    # *Then* flatten them into a stream of single lines
    flattened = chain.from_iterable(interleaved)
    # Filter out the None padding added by grouper() and
    # read the lines into a list
    lines = list(filter(lambda x: x is not None, flattened))

Обратите внимание, что пока вы не вызовете list, вы на самом деле ничего не читаете из файлов; вы просто создаете функциональный конвейер, который будет обрабатывать ввод по требованию.


Для справки: определения grouper и roundrobin скопированы из документация.

# From itertools documentation
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)


# From itertools documentation
def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))
1
chepner 18 Апр 2019 в 16:34

Я закончил с чем-то очень похожим на Чепнер ...

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

def read_blocks(path, nlines):
    with open(path) as fd:
        out = []
        for line in fd:
            out.append(line)
            if len(out) == nlines:
                yield out
                out = []
        if out:
            yield out

Затем я определяю функцию, которая чередует выходные данные набора итераторов (т. Е. Так же, как roundrobin из chepner, я нахожу версию в itertools несколько непрозрачной):

def interleave(*iterables):
    iterables = [iter(it) for it in iterables]
    i = 0
    while iterables:
        try:
            yield next(iterables[i])
        except StopIteration:
            del iterables[i]
        else:
            i += 1
        if i >= len(iterables):
            i = 0

Затем мы определяем функцию для объединения вышеперечисленного:

def read_files_in_blocks(filenames, nlines):
    return interleave(*(read_blocks(path, nlines) for path in filenames))

И назовите это с некоторыми фиктивными данными:

filenames = ['foo.txt', 'bar.txt', 'baz.txt']

for block in read_files_in_blocks(filenames, 5):
    for line in block:
        print(line)
0
Sam Mason 18 Апр 2019 в 16:34