Могу ли я использовать itertools.groupby для возврата групп строк, где первая строка начинается с определенного символа?

У меня есть текстовый файл, который выглядит так:

>Начало группы

текст 1

текст2

>Начало новой группы

текст3

Я пытался использовать itertools.groupby для возврата групп, где каждая группа представляет собой список списков, содержащих:

1) строка, начинающаяся с символа «>».

2) строки текста, следующие за строкой, начинающейся с символа «>», до следующей строки, начинающейся с символа «>».

Итак, из предыдущего текста я ХОЧУ получить:

[['>Start of group', text1, text2], ['>Start of new group', text3]]

Код, который я написал до сих пор:

with open(filename) as rfile:
    groups = []

    for key, group in groupby(rfile, lambda x: x.startswith(">")):
        groups.append(list(group))

Однако это создает список списков, где каждая строка файла находится в своем собственном списке, например:

[['>Start of group'],[text1],[text2],['>Start of new group'],[text3]]

Я думаю, что, вероятно, просто не очень хорошо понимаю функцию groupby, так как я впервые пытаюсь ее реализовать, поэтому любое объяснение приветствуется.


person boseHere    schedule 19.05.2019    source источник
comment
itertools.groupby имеет группы элементов с общими характеристиками, например. сгруппировать все прописные буквы, сгруппировать все слова, начинающиеся с foo. Здесь было бы сложнее использовать, так как вы действительно просто хотите разделить строку до некоторого условия. См. здесь когда использовать groupby   -  person pylang    schedule 20.05.2019


Ответы (3)


Вот способ получить ваши данные без функции groupby.

fin = open('fasta.out', 'r')

data = []

for line in fin:
    line = line.rstrip()

    if line.startswith('>'):
        data.append([line])
    else:
        data[-1].append(line)
person Chris Charley    schedule 19.05.2019
comment
Немного чище: if line.startswith('>'): data.append([]); data[-1].append(line). - person chepner; 20.05.2019

groupby группирует элементы в итерируемом объекте по некоторому предикату, который применяется к каждому элементу. Это означает, что предикат группировки должен иметь возможность идентифицировать функцию, по которой группируется, взглянув только на один элемент. Поскольку ваши данные не позволяют (вы должны просмотреть предыдущие элементы, чтобы определить ключ группировки), это не лучший кандидат для использования groupby, и ответ Криса Чарли является более чистым решением.

Тем не менее, если вы смотрите на это как на задачу кодирования, а не на решение реальной проблемы, вы можете создать функцию группировки, которая сохраняет состояние и отслеживает последнюю увиденную метку группы. Класс, который реализует __call__ и сохраняет последнюю метку группы, видимую как свойство, и возвращает, что, когда следующий ввод не является меткой группы, можно достичь того, что вы ищете.

person jbryan    schedule 19.05.2019

Суть в том, чтобы пометить каждую строку в одной группе одним и тем же номером, что можно сделать с помощью другого генератора. Считайте это демонстрацией того, как работает groupby, а не практическим советом; вместо этого используйте ответ Криса Чарли.

def number_lines(txt):
    i = 0
    for line in text:
        if line.startswith(">"):
            i += 1
        yield (1, line)

Обратите внимание, что последовательность кортежей, созданных number_lines, автоматически сортируется по первому элементу кортежа. Чтобы сгруппировать их, скажите groupby использовать первый элемент в качестве «группового тега».

from operator import itemgetter

with open(filename) as rfile:
    numbered_lines = number(rfile)
    groups = [[line for n, line in group]
              for number, group in groupby(numbered_lines, itemgetter(0))]
person chepner    schedule 19.05.2019