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

时间:2015-06-28 22:55:49

标签: 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:
        f.writelines(heapq.merge(*files))

问题是如何处理文件中的空行。例如:

  

DATA1.TXT:

     

苹果

     

亚马逊

     

谷歌

     

Data2.txt:

     

您好

     

今天

     

世界

Output:

apple 
amazon 
google 
hello 
today 
world

我不使用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)

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

1 个答案:

答案 0 :(得分:3)

如果要在跳过空白行时使用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))

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