合并多个已排序的大文件--python

合并多个已排序的大文件--python,python,algorithm,sorting,merge,mergesort,Python,Algorithm,Sorting,Merge,Mergesort,任务是合并排序两个大文件(无法放入内存)。在做了一些研究之后,使用heapq.merge import heapq import contextlib filenames=('data1.txt', 'data2.txt') with contextlib.ExitStack() as stack: files = [stack.enter_context(open(fn)) for fn in filenames] with open('data', 'w') as f:

任务是合并排序两个大文件(无法放入内存)。在做了一些研究之后,使用
heapq.merge

import heapq
import contextlib

filenames=('data1.txt', 'data2.txt')
with contextlib.ExitStack() as stack:
    files = [stack.enter_context(open(fn)) for fn in filenames]
    with open('data', 'w') as f:
        f.writelines(heapq.merge(*files))
问题是如何处理文件中的空行。例如:

Data1.txt:

苹果

亚马逊

谷歌

Data2.txt:

你好

今天

世界

我对不使用heapq.merge的回答:

def read_non_empty_line(input):
    while True:
        line = input.readline()
        if line == "":
            return ""
        if line.isspace() == False:
            return line.strip()
    #return line

def combine_sorted_files(file1, file2, output):

    read_file1, read_file2 = True, True

    with open(output,'w') as output_file:
        with open(file1,'r') as input_file1:
            with open(file2,'r') as input_file2:
                while True:
                    if read_file1:
                        line1 = read_non_empty_line(input_file1)
                    if read_file2:
                        line2 = read_non_empty_line(input_file2)

                    if line1 == "" or line2 == "":
                        break

                    read_file1, read_file2 = False, False
                    if line1 < line2:
                        smaller = line1
                        read_file1 = True
                    else:
                        smaller = line2
                        read_file2 = True

                    output_file.write(smaller+"\n\n")

                while line1 != "":
                    output_file.write(line1+"\n\n")
                    line1 = read_non_empty_line(input_file1)
                while line2 != "":
                    output_file.write(line2+"\n\n")
                    line2 = read_non_empty_line(input_file2)
def读取非空行(输入):
尽管如此:
line=input.readline()
如果行==“”:
返回“”
如果line.isspace()==False:
返回行.strip()
#回程线
def合并已排序的文件(文件1、文件2、输出):
read_file1,read_file2=True,True
将open(output,'w')作为输出文件:
以open(file1,'r')作为输入\u file1:
以open(file2,'r')作为输入\u file2:
尽管如此:
如果读取文件1:
line1=读取\非\空\行(输入\文件1)
如果读取文件2:
line2=读取\非\空\行(输入\文件2)
如果第1行==“”或第2行==“”:
打破
read_file1,read_file2=False,False
如果第1行<第2行:
较小=第1行
read_file1=True
其他:
较小=第2行
read_file2=True
输出文件。写入(较小的+“\n\n”)
而第1行!="":
输出文件。写入(第1行+“\n\n”)
line1=读取\非\空\行(输入\文件1)
而第2行!="":
输出文件。写入(第2行+“\n\n”)
line2=读取\非\空\行(输入\文件2)

这个问题还要求优化内存和CPU利用率。有什么建议吗?

如果要在跳过空行时使用
heapq.merge
,可以创建自己的生成器函数来处理跳过逻辑:

def iterate_non_blank_lines(file_iterator):
    for line in file_iterator:
        if line != "":
            yield line
注意:我只是检查了空行,但您可以在这里轻松地使用正则表达式跳过仅包含空格的行

然后可以修改代码以使用此生成器:

filenames=('data1.txt', 'data2.txt')
with contextlib.ExitStack() as stack:
    files = [iterate_non_blank_lines(stack.enter_context(open(fn))) for fn in filenames]
    with open('data', 'w') as f:
        f.writelines(heapq.merge(*files))

此外,这个问题听起来很像家庭作业问题(如果不是,则为同位语),我强烈建议您自己实现合并逻辑,因为这是一个有趣的问题。

heapq.merge
仅适用于已排序的输入数据。你的数据文件已经分类了吗?@SamuelO'Malley是的!这是家庭作业问题吗?如果是这样的话,我强烈建议您自己尝试在不使用
heapq.merge
的情况下实现这一点,因为这不是很难,而且会使跳过空行变得非常容易。@SamuelO'Malley,明白了。我将在没有heaq.merge的情况下实现它,然后发布它。在那之后,你能回答这个问题吗?我对使用heaq.merge也很感兴趣。我会给heapq.merge一个答案,如果它不起作用,请告诉我。非常感谢!是的,实现合并逻辑很有趣。我正在做。:-)
filenames=('data1.txt', 'data2.txt')
with contextlib.ExitStack() as stack:
    files = [iterate_non_blank_lines(stack.enter_context(open(fn))) for fn in filenames]
    with open('data', 'w') as f:
        f.writelines(heapq.merge(*files))