我正在尝试学习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))
答案 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