【问题标题】:Scala : File reading to Build an external Merge SortScala:文件读取以构建外部合并排序
【发布时间】:2018-02-12 21:18:00
【问题描述】:

我想在 Scala 中实现一个外部合并排序。它用于对无法完全放入主内存的大文件进行排序。

详情可以在这里找到:- How external merge sort algorithm works?

现在,我需要读取文件块,对其进行排序并将其写入磁盘等

分段读取/写入大文件的最惯用/最实用的方式是什么?

  • 如果我使用 'Source.fromFile(filename).getLines' 方法,我知道我会在文件上获得一个迭代器,并且可以部分读取它。但是当我得到一个迭代器时,在主内存中读取了多少文件?是否可以从中读取固定数量的字节?
  • 关于如何实现此功能的任何其他建议?可能有一些指向 fs2(scalaz-stream)/Akka Stream / Monix 实现的指针,我可以将文件视为 Stream 并以块的形式读取?

【问题讨论】:

    标签: scala functional-programming akka-stream fs2


    【解决方案1】:

    分块排序/写入

    假设您想一次将 N 个数字保存在内存中,并进一步假设给您一个函数,该函数将 N 个排序后的数字写入文件:

    val N : Int = ???
    
    val writeToFile : Seq[Int] => Unit = ???
    

    如您的问题所示,迭代器可用于一次仅将 N 个数字保留在 RAM 中,以对它们进行排序并将它们写入中间文件:

    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]] = ???
    

    我们可以编写一个函数,该函数将返回一个新的迭代器,该迭代器从每个文件中获取值并对其进行排序:

    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]作为结果。

    【讨论】:

    • 伙计,我正在考虑将其作为 1 个月的副业项目。但看起来你在 15 分钟内为我完成了大部分工作。你的帽子!辉煌而鼓舞人心的东西:)
    • 您认为我们可以通过进行 k 路合并而不是每次都对列表​​进行排序来提高性能吗? (在合并阶段)
    • @AarshShah 我不知道你所说的“k-way merge”是什么意思。 mergeSort 的每次迭代都会从每个非空子文件中读取一个整数,并在再次从磁盘读取之前对这些整数进行排序。这就是你要找的东西吗?
    • 我说的是不完美排序的解决方案。 k 路合并用于将 K 个已排序的 List 合并为一个已排序的 List 。它在外部排序中的应用在此处的第 5 步中给出:- en.m.wikipedia.org/wiki/External_sorting
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    相关资源
    最近更新 更多