[英]Fast Functional Equivalent Of For Loop Scala
I have the following two code snippets in Scala: 我在Scala中有以下两个代码段:
/* Iterative */
for (i <- max to sum by min) {
if (sum % i == 0) validBusSize(i, L, 0)
}
/* Functional */
List.range(max, sum + 1, min)
.filter(sum % _ == 0)
.map(validBusSize(_, L, 0))
Both these code snippets are part of otherwise identical objects. 这两个代码段都是其他相同对象的一部分。 However, when I run my code on Hackerrank, the object with the iterative snippet takes a maximum of 1.45 seconds, while the functional snippet causes the code to take > 7 seconds, which is a timeout.
但是,当我在Hackerrank上运行代码时,带有迭代代码段的对象最多花费1.45秒,而功能代码段导致代码花费> 7秒,这是超时。
I'd like to know if it's possible to rewrite the for loop functionally while retaining the speed. 我想知道是否可以在保持速度的同时在功能上重写for循环。 I took a look at the
Stream
container, but again I'll have to call filter
before map
, instead of computing each validBusSize
sequentially. 我看了看
Stream
容器,但是我还是不得不在map
之前调用filter
,而不是依次计算每个有效的validBusSize
。
Thanks! 谢谢!
Edit: 编辑:
/* Full Code */
import scala.io.StdIn.readLine
object BusStation {
def main(args: Array[String]) {
readLine
val L = readLine.split(" ").map(_.toInt).toList
val min = L.min
val max = L.max
val sum = L.foldRight(0)(_ + _)
/* code under consideration */
for (i <- max to sum by min) {
if (sum % i == 0) validBusSize(i, L, 0)
}
}
def validBusSize(size: Int, L: List[Int], curr: Int) {
L match {
case Nil if (curr == size) => print(size + " ")
case head::tail if (curr < size) =>
validBusSize(size, tail, curr + head)
case head::tail if (curr == size) => validBusSize(size, tail, head)
case head::tail if (curr > size) => return
}
}
}
Right now, your best bet for fast functional code is tail-recursive functions: 现在,对快速功能代码最好的选择是尾递归函数:
@annotation.tailrec
def getBusSizes(i: Int, sum: Int, step: Int) {
if (i <= sum) {
if (sum % i == 0) validBusSize(i, L, 0)
getBusSizes(i + step, sum, step)
}
}
Various other things will be sort of fast-ish, but for something like this where there's mostly simple math, the overhead from the generic interface will be sizable. 各种其他事情都会很快,但是对于像这样的事情,大多数是简单的数学运算,通用接口的开销将是可观的。 With a tail-recursive function you'll get a while loop underneath.
使用尾递归功能,您将在下面获得while循环。 (You don't need the annotation to make it tail-recursive; that just causes the compilation to fail if it can't. The optimization happens whether the annotation is there or not.)
(您不需要注释使它成为尾递归;这只会导致编译失败,否则会失败。无论是否存在注释,都会进行优化。)
So apparently the following worked: 因此,显然以下工作:
Replacing the List.range(max, sum + 1, min)
with a Range object, (max to sum by min)
. 用Range对象替换
List.range(max, sum + 1, min)
(max to sum by min)
。 Going to ask another questions about why this works though. 还要问另一个问题,为什么会这样。
Consider converting the range into a parallel version with keyword par
, for instance like this 考虑将范围转换为带有关键字
par
的并行版本,例如这样
(max to sum by min).par
This may improve performance especially for large sized ranges with large values on calling validBusSize
. 这可能会提高性能,尤其是对于在调用
validBusSize
具有较大值的较大范围的validBusSize
。
Thus in the proposed for comprehension, 因此,在拟议的理解中,
for ( i <- (max to sum by min).par ) {
if (sum % i == 0) validBusSize(i, L, 0)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.