我有一个文本文件,如下所示:
>组开始
text1
text2
>开始新群组
text3
我一直试图使用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函数,因为这是我第一次尝试实现它,所以可以理解任何解释。
答案 0 :(得分:2)
这是一种无需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)
答案 1 :(得分:0)
groupby
通过应用于每个元素的某些谓词将项以可迭代方式分组。这意味着分组谓词必须能够仅通过查看一个元素来识别正在分组的要素。由于您的数据不允许(您必须查看前面的元素来确定分组键),因此这不是使用groupby
的理想选择,克里斯·查理(Chris Charley)的答案是一种更干净的解决方案。
也就是说,如果您将其视为编码挑战而不是解决实际问题,则可以创建一个分组函数来存储状态并跟踪最后看到的分组标签。一个实现__call__
并存储最后一个组标签的类,该组标签被视为一个属性,并返回当下一个输入不是组标签时可以实现的功能。
答案 2 :(得分:0)
关键是用相同的编号标记同一组中的每一行,这可以由另一台生成器完成。考虑一下groupby
的工作方式的演示,而不是实际的建议;改用Chris Charley的答案。
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))]