实现外部合并排序

时间:2015-05-27 21:54:15

标签: python sorting

我正在尝试学习Python,并正在使用带有整数的输入文件进行外部合并排序。我正在使用heapq.merge,我的代码几乎可以工作,但它似乎是将我的行排序为字符串而不是整数。如果我尝试转换为int,则writelines将不接受数据。任何人都可以帮我找到替代方案吗?另外,我认为这样可以让我对一个比内存更大的文件(给定足够的磁盘空间)进行排序

import itertools
from itertools import islice
import tempfile
import heapq

#converts heapq.merge to ints
#def merge(*temp_files):
#    return heapq.merge(*[itertools.imap(int, s) for s in temp_files])

with open("path\to\input", "r") as f:
    temp_file = tempfile.TemporaryFile()
    temp_files = []
    elements = []
    while True:
        elements = list(islice(f, 1000))
        if not elements:
           break
        elements.sort(key=int)
        temp_files.append(elements)
        temp_file.writelines(elements)
        temp_file.flush()
        temp_file.seek(0)
        with open("path\to\output", "w") as output_file:
            output_file.writelines(heapq.merge(*temp_files))

3 个答案:

答案 0 :(得分:2)

默认情况下,您的元素会被读取为字符串,您必须执行以下操作:

elements = list(islice(f, 1000))
elements = [int(elem) for elem in elements]

这样它们就会被解释为整数。

这也意味着你需要在写作时将它们转换回字符串,例如:

temp_file.writelines([str(elem) for elem in elements])

除此之外,您还需要将元素再次转换为int以进行最终合并。在您的情况下,您可能想要取消注释merge方法(然后再将结果转换回字符串,与上面相同)。

答案 1 :(得分:1)

您的代码对我来说没有多大意义(temp_files.append(elements)?在循环中合并?),但这是一种合并文件排序的方法:

import heapq
files = open('a.txt'), open('b.txt')
with open('merged.txt', 'w') as out:
    out.writelines(map('{}\n'.format,
                       heapq.merge(*(map(int, f)
                                     for f in files))))

首先map(int, ...)将每个文件的行转换为整数。然后那些与heapq.merge合并。然后map('{}\n'.format将每个整数转换回字符串,换行。然后writelines写下这些行。换句话说,你已经很接近了,只需要在写入之前将int转换回字符串。

写一种不同的方式(对某些人来说可能更清楚):

import heapq
files = open('a.txt'), open('b.txt')
with open('merged.txt', 'w') as out:
    int_streams = (map(int, f) for f in files)
    int_stream = heapq.merge(*int_streams)
    line_stream = map('{}\n'.format, int_stream)
    out.writelines(line_stream)

在任何情况下,如果您使用的是Python 2,请使用itertools.imap,否则它会立即将整个文件读入内存。在Python 3中,您可以使用普通的map

是的,如果你做对了,这将允许你用很少的内存对巨大的文件进行排序。

答案 2 :(得分:0)

您正在循环中进行 Kway 合并,这将添加很多 runtimeComplexity 。更好地将文件句柄存储到spearate列表中,并执行 Kway 合并

您也不必删除并添加新行,只需根据数字对其进行排序。

  

已排序(temp_files,key = lambda no:int(no.strip()))

其他事情都没事。

https://github.com/melvilgit/external-Merge-Sort/blob/master/README.md