список списков из файла: каждые 4 строки

Я читаю из файла на Python и мне нужно создать список списков. Каждая строка представляет собой отдельное значение в записи, каждая запись отделяется пустой строкой \n.

rsfile = 'filepath.txt'
l_s = [[line.rstrip('\n') for line in fileinput.input([rsfile]) if line != '\n']]

Это дает мне список значений для каждой строки и исключает \n, однако я хотел бы начать новый подсписок или блок списка в более крупном списке.

например
'строка 1a'
'строка 2a'
'строка 3a'
'\n'
'строка 1b'
'строка 2b'
'строка 3b' < бр>'\n'

[['line 1a', 'line 2a', 'line 3a'], ['line 1b', 'line 2b', 'line 3b']]

Возможно ли это с пониманием списка? Я изначально создавал это с двумя списками

for line in file:
    if line != '\n': l.append(line)

    else: l_of_l.append(l)

    l = []

Спасибо за помощь!

Стивен


person sbitaxi    schedule 01.04.2013    source источник
comment
Я не уверен, хотите ли вы каждые 4 строки, или каждую группу, разделенную пустой строкой, или что-то другое. Но я уверен, что itertools — это то, что вам нужно. Либо функция grouper из рецептов в документации, либо тривиальная однострочная запись вокруг groupby.   -  person abarnert    schedule 02.04.2013


Ответы (3)


Если вы пытаетесь собрать вещи в группы из 4 строк, функция grouper в itertools recipes делает это тривиальным:

groups = grouper(4, file)

Это возвращает вам итерацию итераций — в частности, izip ленивый итератор по tuples. Если вам конкретно нужен список списков, вам нужно сделать что-то вроде:

groups = [list(group) for group in grouper(4, file)]

Поскольку рецепты не являются частью модуля стандартной библиотеки, вам нужно либо скопировать и вставить функцию из документации, либо установить сторонний модуль с именем more_itertools.

Если вы хотите что-то немного другое... ну, трудно точно знать, как это закодировать, не зная точно, что вы хотите, но вы, вероятно, найдете это в itertools.

Например, допустим, вы хотите разбить его на группы, разделенные линиями, которые представляют собой не что иное, как пробелы. Я почти уверен, что в more_itertools есть функция, которая делает это за вас, но вы можете довольно легко написать ее сами.

Во-первых, вы можете использовать groupby для группировки строк по они все пробелы:

groups = itertools.groupby(file, lambda line: not line.strip())

Но groupby возвращает key, group пар. Вам нужен только group без key. И вам также нужны только группы непустых строк, а не все группы.

groups = [group for empty, group 
          in itertools.groupby(file, lambda line: not line.strip())
          if not empty]

Или, если вам явно нужен список списков, а не какой-то произвольный итерируемый тип (в данном случае список _grouper ленивых итераций):

groups = [list(group) for empty, group 
          in itertools.groupby(file, lambda line: not line.strip())
          if not empty]

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

Я бы, вероятно, выделил lambda line: not line.strip() в функцию (или использовал more_functools.negate(line.strip), или…) и записал ее в виде двух или трех строк вместо того, чтобы втискивать ее в большой список, но если вам нужно однострочное понимание списка (и 98-символьная строка приемлема), вот и все.

person abarnert    schedule 01.04.2013
comment
Абарнерт, я еще не использовал itertools, поэтому я довольно незнаком с его функциями, но после вашего поста я начал просматривать функции в модуле. Это определенно должен быть список списков, и он определенно работает быстрее, чем любое другое решение, которое я придумал. Мне нужно потратить некоторое время на это. Благодарю вас! - person sbitaxi; 03.04.2013
comment
@sbitaxi: В Python, если вы можете думать о том, как преобразовать один итератор в другой итератор, а не о том, что делать внутри цикла, вы часто обнаружите, что itertools выполняет 90% тяжелой работы за вас. (Если вы не занимаетесь арифметикой, в этом случае вместо этого будет numpy.) Но это другой способ мышления. У Дэвида Бизли два слайд-шоу, которые хорошо передают идею, и после этого вы найдете itertools еще круче. - person abarnert; 03.04.2013

У вас есть пустые строки, разделяющие группы, которые должны входить в каждый подсписок, верно? Предполагая, что ваш ввод не слишком огромен, чтобы прочитать его сразу, вы можете сделать это следующим образом:

mylines = open("filepath.txt").read()
groups = [ grp.split("\n") for grp in mylines.split("\n\n") ]

Первый split дает вам группы из трех строк (или что-то еще), второй строит подсписок из каждой группы.

person alexis    schedule 01.04.2013
comment
Алексис, это именно то, что я искал. Благодарю вас! Я должен был придумать это, найдя экземпляры \n\n. - person sbitaxi; 03.04.2013
comment
Пожалуйста. Если теперь вы считаете это лучшим ответом на свой вопрос, вы можете изменить принятый ответ ;-) - person alexis; 03.04.2013

Попробуйте что-то вроде этого... это работает. "f.txt" - это ваш файл для чтения

f=open('f.txt','r')
list=[[]]
i=0
for line in f:
    if line!='\n':
        list[i].append(line.strip('\n'))
    else:
        list.append([])
        i=+1
        print i
print list
person Viktor    schedule 01.04.2013
comment
Спасибо, Виктор, но это то, с чего я начал и вместо этого пытался сделать это с пониманием списка. Я очень ценю, что вы тоже нашли время, чтобы дать представление об альтернативных методах. - person sbitaxi; 03.04.2013