我可以使用 itertools.groupby 到 return 行组,其中第一行以特定字符开头吗?

Can I use itertools.groupby to return groups of lines where the first line starts with a specific character?

我有一个如下所示的文本文件:

>Start of group

text1

text2

>Start of new group

text3

我一直在尝试使用 itertools.groupby 到 return 组,其中每个组都是一个列表列表,其中包含:

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 函数,因为这是我第一次尝试实现它,因此不胜感激。

这是一种无需 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)

groupby 通过应用于每个元素的某些谓词将可迭代项中的项目分组。这意味着分组谓词必须能够通过仅查看一个元素来识别要分组的特征。由于您的数据不允许(您必须查看前面的元素来确定分组键),这不是使用 groupby 的好选择,而 Chris Charley 的答案是一个更清晰的解决方案。

就是说,如果您将此视为编码挑战而不是解决现实世界的问题,则可以创建一个分组函数来存储状态并跟踪看到的最后一个组标签。实现 __call__ 并将最后一个组标签存储为 属性 和 returns 的 class 当下一个输入不是组标签时可以实现您正在寻找的内容.

关键是用相同的数字标记同一组中的每一行,这可以用另一个生成器来完成。将此视为 groupby 工作原理的演示,而不是实用建议;请改用 Chris Charley 的回答。

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

注意 number_lines 生成的元组序列自动按元组的第一个元素排序。为了对它们进行分组,告诉 groupby 使用第一个元素作为 "group tag".

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))]