7

我有这样的Scala代码

var i = 1
for(e <- array) {
    acc += e * i
    i += 1
}

我需要将数组中的第一个元素乘以 1,下一个元素乘以 2,下一个元素乘以 3,依此类推,将其全部添加到累加器中。我觉得在 Scala 中有更好的方法,甚至可以折叠?

4

4 回答 4

15

“更好”取决于你的目标是什么。简短而清晰?大概

{ for (i <- array.indices; e = array(i)) yield (i+1)*e }.sum

或者

array.indices.map(i => (i+1)*array(i)).sum

(或者稍微快一点,因为您可以随时创建中间体:

array.indices.iterator.map(i => (i+1)*array(i)).sum

)。

你通常应该简短而清晰。

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

var i = 0
var acc = 0
while (i < array.length) {
  acc += (i+1)*array(i)
  i += 1
}

或使用递归

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)
于 2013-03-05T16:01:41.837 回答
10

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

array.zipWithIndex.map { case (e, i) => e * (i + 1) }.sum
于 2013-03-05T15:31:33.253 回答
5
val x = List(1,1,1,1,1,1)
(((0,1) /: x){case ((acc, mult), l) => (acc + (l * mult), mult + 1) })._1

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

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

于 2013-03-05T15:27:12.293 回答
2

我不确定我的建议是否是一种更好的方法,因为它更实用(==它会执行得更慢):

(0 /: (array zipWithIndex)) {(a, i) => (i._1 * (i._2 + 1)) + a}

这确实对由http://www.scala-lang.org/api/current/index.html#scala.Array中的 zipWithIndex 方法生成的数组执行 foldLeft

zipWithIndex 只是用它们的索引压缩集合的元素。

于 2013-03-05T15:36:24.503 回答