0

这是一个查找第三大整数集合的函数。我这样称呼它:

val lineStream = thirdLargest(Source.fromFile("10m.txt").getLines.toIterable
val intStream = lineStream map { s => Integer.parseInt(s) }
thirdLargest(intStream) 

该文件10m.txt包含 1000 万行,每行都有一个随机整数。下面的thirdLargest函数在测试之后不应该保留任何整数,但它会导致 JVM 内存不足(在我的情况下大约 90 秒后)。

def thirdLargest(numbers: Iterable[Int]): Option[Int] = {
    def top3of4(top3: List[Int], fourth: Int) = top3 match {
        case List(a, b, c) =>
            if (fourth > c) List(b, c, fourth)
            else if (fourth > b) List(b, fourth, c)
            else if (fourth > a) List(fourth, b, c)
            else top3
    }

    @tailrec
    def find(top3: List[Int], rest: Iterable[Int]): Int = (top3, rest) match {
        case (List(a, b, c), Nil) => a
        case (top3, d #:: rest) => find(top3of4(top3, d), rest)
    }

    numbers match {
        case a #:: b #:: c #:: rest => Some(find(List[Int](a, b, c).sorted, rest))
        case _ => None
    }
}
4

1 回答 1

2

OOM 错误与您读取文件的方式无关。完全没问题,甚至建议在Source.getLines这里使用。问题在别处。

Stream许多人对 Scala概念的本质感到困惑。事实上,这不是你想要用来迭代事物的东西。它确实很懒,但它不会丢弃以前的结果——它们被记忆了,所以下次使用时不需要重新计算它们(这在你的情况下永远不会发生,但这就是你的记忆所在)。另请参阅此答案

考虑使用foldLeft. 这是一个用于说明目的的工作(但有意简化)示例:

val lines = Source.fromFile("10m.txt").getLines()

print(lines.map(_.toInt).foldLeft(-1 :: -1 :: -1 :: Nil) { (best3, next) =>
  (next :: best3).sorted.reverse.take(3)
})
于 2013-10-31T18:13:19.250 回答