迭代的哪种构造最好在Scala中使用?

时间:2014-09-30 10:50:36

标签: performance scala coding-style

最近,我开始在Scala编写很多编程竞赛代码。 (您可以在这里查看平台 - http://codeforces.com/

关于问题的本质,我经常需要迭代数组或输入数据。例如。有一个问题陈述,说,在第一个输入行我会得到数字M,然后我需要读取M行,或整数或其他什么。我尝试使用不同的方法:

for (i <- 0 until M)
---- 
(0 until M).foreach
----
var i = 0
while (i < M)
---

甚至尾递归

@tailrec
  def recursion(i: Int): Unit = {
    if (i < M) {
      doSomething()
      recursion(i + 1)
    }
  }

所以,我的问题是哪种结构更适合Scala风格,以及更好的性能? (我正在解决的问题通常需要快速执行,否则它们不会被传递)

P.S。 我为此写了一个小测试,看起来虽然和tailrec是最好的表演者,但不是一件大事。你可以在这里看一下 - https://gist.github.com/MysterionRise/5daa63fdbd5d058528fe

2 个答案:

答案 0 :(得分:3)

我会按照以下顺序为它们评价样式:

  • 为/的foreach
  • 尾递归
  • 当务之急(最后一种方式)

关于性能尾部递归和命令式将使你像循环一样快(tailrec在实践中变得非常接近while循环),并且比for / foreach更快。

附注:如果您要使用ideomatic Sc​​ala,您可能希望尝试避免副作用,而是使用.map或使尾部递归函数返回某些内容而不是改变某些内容。

答案 1 :(得分:3)

关于效果:

请注意,如果要在JVM上编写适当的微基准,则必须考虑many effects - 例如,当JVM开始使用JIT时,同一段代码的性能会有所不同编译,然后尝试不同的优化。要在Scala中编写适当的基准,您可以查看像ScalaMetercaliper这样的库。顺便说一句,第二个链接比较了Scala循环的不同方式,因此应该很容易适应您的用例。

但是,一般来说:

  • 尾递归解决方案将针对由等效while循环生成的相同类型的字节码进行优化,因此两者应始终相似(如果代码实际上相同)。
  • for循环是对foreach方法的调用的语法糖,所以这两者应该是严格等价的。
  • foreach(或for循环)稍微慢于等效的while循环(或尾递归):我上面链接的benchmark显示15x性能差异,1000次迭代(尽管它可能取决于Scala的版本和JRE的版本......)。但是如果循环中的代码执行的时间比循环本身要长得多,那么这种差异将变得可以忽略不计,因此这并不意味着它总是相关的。

关于风格:

我完全同意约翰丹德的回答。