我有一个大约100Mb的文件,如下所示:
#meta data 1
skadjflaskdjfasljdfalskdjfl
sdkfjhasdlkgjhsdlkjghlaskdj
asdhfk
#meta data 2
jflaksdjflaksjdflkjasdlfjas
ldaksjflkdsajlkdfj
#meta data 3
alsdkjflasdjkfglalaskdjf
此文件包含一行元数据,这些元数据对应于仅包含字母数字字符的多个可变长度数据。将这些数据读入这样一个简单列表的最佳方法是什么:
data = [[#meta data 1, skadjflaskdjfasljdfalskdjflsdkfjhasdlkgjhsdlkjghlaskdjasdhfk],
[#meta data 2, jflaksdjflaksjdflkjasdlfjasldaksjflkdsajlkdfj],
[#meta data 3, alsdkjflasdjkfglalaskdjf]]
我最初的想法是使用read()
方法将整个文件读入内存,然后使用正则表达式将数据解析为所需的格式。是否有更好的pythonic方式?所有元数据行都以octothorpe开头,所有数据行都是字母数字。谢谢!
答案 0 :(得分:4)
itertools.groupby提供了一种简单的方法来将行收集到组中:
import itertools
data=[]
with open('data.txt','r') as f:
for key,group in itertools.groupby(f,lambda line: line.startswith('#meta')):
if key:
meta=next(group).strip()
else:
lines=''.join(group).strip()
data.append((meta,lines))
print(data)
产量
[('#meta data 1', 'skadjflaskdjfasljdfalskdjfl\nsdkfjhasdlkgjhsdlkjghlaskdj\nasdhfk'), ('#meta data 2', 'jflaksdjflaksjdflkjasdlfjas\nldaksjflkdsajlkdfj'), ('#meta data 3', 'alsdkjflasdjkfglalaskdjf')]
表达式
itertools.groupby(f,lambda line: line.startswith('#meta'))
返回一个迭代器。它循环遍历f
中的行,并在每行上调用lambda
函数。当遇到以#meta
开头的行时,该函数返回True
,否则返回False
。
itertools.groupby
收集返回相同值的所有连续行。
因此以#meta
开头的行放在自己的组中,然后所有不以#meta
开头的后续行都放在下一组中,依此类推。
key
是lambda
函数的返回值。在这种情况下,它将是True
或False
。
答案 1 :(得分:1)
我不知道这是否是最快的方式,但从我的头脑中开始:
data = []
with open('input.file', 'r') as fp:
for line in fp:
line = line.strip()
if line[0] == '#':
data.append((line, []))
else:
data[-1][1].append(line)
data = [(X, ''.join(Y)) for X, Y in data]
答案 2 :(得分:0)
我猜是这样的:
result = []
for line in file.readlines():
if line[0] == '#':
result.append([line])
else:
if len(result[-1]) == 1:
result[-1].append(line)
else:
result[-1][-1] += line
未经测试。
答案 3 :(得分:0)
我会保持简单,例如:
data = [] # result
lastmeta = None # the last metadata line seen
chunks = [] # lines since the last metadata line
for line in input:
if line[0] == '#': # metadata
if lastmeta: # need to flush data we've collected
data.append((lastmeta, ''.join(chunks))
lastmeta = line
else:
chunks.append(line)