我想在Scala中实现外部合并排序。它用于对大型文件进行排序,这些文件完全不适合主内存。
详情可在此处找到: - How external merge sort algorithm works?
现在,我需要读取文件的块,对其进行排序并将其写入磁盘等等
在部分中读取/写入大文件的最惯用/最实用的方法是什么?
答案 0 :(得分:2)
分块排序/写作
假设您希望一次在内存中保留N个数字,并进一步假设您有一个函数将N个已排序的数字写入文件:
val N : Int = ???
val writeToFile : Seq[Int] => Unit = ???
如您的问题中所示,Iterator可以用于一次仅在RAM中保留N个数字以对它们进行排序并将它们写入中间文件:
val sourceFileName : String = ???
val sortAndWrite : Seq[Int] => Unit =
(_.sorted) andThen writeToFile
Source
.fromFile(sourceFileName)
.getLines
.map(_.toInt)
.grouped(N)
.foreach(sortAndWrite)
现在,您将每组N个数字放在不同的文件中。剩下要做的就是将文件合并在一起。
<强>合并强>
给定一些读取函数,从每个子文件返回迭代器:
val subFiles : Iterable[Iterator[String]] = ???
我们可以编写一个函数来返回一个新的Iterator,它从每个文件中获取值并对它们进行排序:
val mergeSort : Iterable[Iterator[String]] => Iterator[Int] =
(fileIterators) => {
val nonEmptyFiles = fileIterators filter (_.hasNext)
nonEmptyFiles
.map(_.next)
.map(_.toInt)
.sorted
.toIterator ++ mergeSort(nonEmptyFiles)
}
注意:上面的函数会在每个文件的内存中保留一个Integer
,因此RAM的使用取决于writeToFile
创建的不同文件的数量。
现在只需将值写入文件:
val destinationFileName : String = ???
val writer : Writer = new FileWriter(destinationFileName)
mergeSort(subFiles) foreach (i => writer write i.toString)
不完整的排序
有一点需要注意:如果N很小并且源文件不够随机,那么解决方案将不会产生完美的排序。示例:假设N = 2
且初始列表为[10,11,0,1]
,那么算法在一次通过后会生成[0,10,1,11]
作为结果。