在foldLeft中递增变量

chr*_*inx 7 arrays scala increment accumulator

我有像这样的Scala代码

var i = 1
for(e <- array) {
    acc += e * i
    i += 1
}
Run Code Online (Sandbox Code Playgroud)

我需要将数组中的第一个元素乘以1,将下一个元素乘以2,将下一个元素乘以3,然后将它们全部添加到累加器中.我觉得在Scala中有更好的方法,甚至可以折叠?

Rex*_*err 15

"更好"取决于你的目标是什么.简短明了?大概

{ for (i <- array.indices; e = array(i)) yield (i+1)*e }.sum
Run Code Online (Sandbox Code Playgroud)

要么

array.indices.map(i => (i+1)*array(i)).sum
Run Code Online (Sandbox Code Playgroud)

(或稍微快一点,因为你随时创建中间体:

array.indices.iterator.map(i => (i+1)*array(i)).sum
Run Code Online (Sandbox Code Playgroud)

).

你通常应该简短明了.

快速?然后你需要去老派:

var i = 0
var acc = 0
while (i < array.length) {
  acc += (i+1)*array(i)
  i += 1
}
Run Code Online (Sandbox Code Playgroud)

或使用递归

def sum(a: Array[Int], i: Int = 0, acc: Int = 0): Int =
  if (i >= a.length) acc else sum(a, i+1, (i+1)*a(i) + acc)
sum(array)
Run Code Online (Sandbox Code Playgroud)

  • @Impredicative - 如果你正在进行像整数加法这样的轻量级操作,那么分配元组就不是很大(10倍加速).此外,集合不是专用于基元,这意味着每个整数都必须加框,而递归可以使用基元类型.同样巨大(两者一起提供~20x-30x加速). (4认同)

max*_*xmc 10

我更喜欢zipWithIndex,它更易于阅读:

array.zipWithIndex.map { case (e, i) => e * (i + 1) }.sum
Run Code Online (Sandbox Code Playgroud)


Imp*_*ive 5

val x = List(1,1,1,1,1,1)
(((0,1) /: x){case ((acc, mult), l) => (acc + (l * mult), mult + 1) })._1
Run Code Online (Sandbox Code Playgroud)

换句话说,从累加器0和乘数1开始,折叠列表中的每个元素,将累加器更改为acc + (l * mult)并将乘数递增1.我们也在最后得到最终乘数,所以我们调用._1只是得到累加器.

编辑:正如@RexKerr在下面的答案(和评论)中指出的那样,如果性能是一个主要问题,那么最好使用显式递归方法.