我有一个日志文件列表,其中每个文件中的每一行都有一个时间戳,并且行在每个文件中按升序排列。不同的文件可以有重叠的时间范围,我的目标是将它们组合成一个大文件,按时间戳排序。排序中可能存在联系,在这种情况下,我希望下一行来自输入列表中首先列出的任何文件。
我已经看到了如何使用fileinput
执行此操作的示例(请参阅here),但这似乎将所有文件都读入内存。由于我的文件很大,这将是一个问题。因为我的文件是预先排序的,所以似乎应该有一种方法来合并它们,使用的方法只需要考虑每个文件中最新的未探索行。
答案 0 :(得分:14)
如果标准库中有heapq.merge()
,为什么要自己动手?不幸的是,它没有提供一个关键的论点 - 你必须自己做装饰 - 合并 - 不合理的舞蹈:
from itertools import imap
from operator import itemgetter
import heapq
def extract_timestamp(line):
"""Extract timestamp and convert to a form that gives the
expected result in a comparison
"""
return line.split()[1] # for example
with open("log1.txt") as f1, open("log2.txt") as f2:
sources = [f1, f2]
with open("merged.txt", "w") as dest:
decorated = [
((extract_timestamp(line), line) for line in f)
for f in sources]
merged = heapq.merge(*decorated)
undecorated = imap(itemgetter(-1), merged)
dest.writelines(undecorated)
上面的每一步都是“懒惰”。当我避免file.readlines()
时,根据需要读取文件中的行。同样,装饰过程使用生成器表达式而不是list-comps。 heapq.merge()
也很懒惰 - 每个输入迭代器需要一个项目来进行必要的比较。最后我使用itertools.imap()
,内置的map()的惰性变体用于undecorate。
(在Python 3中map()变得懒惰,所以你可以使用它)
答案 1 :(得分:1)
您想要实现基于文件的merge sort。从两个文件中读取一行,输出旧行,然后从该文件中读取另一行。一旦其中一个文件用尽,输出另一个文件中的所有剩余行。