我有这样的Scala代码
var i = 1
for(e <- array) {
acc += e * i
i += 1
}
我需要将数组中的第一个元素乘以 1,下一个元素乘以 2,下一个元素乘以 3,依此类推,将其全部添加到累加器中。我觉得在 Scala 中有更好的方法,甚至可以折叠?
我有这样的Scala代码
var i = 1
for(e <- array) {
acc += e * i
i += 1
}
我需要将数组中的第一个元素乘以 1,下一个元素乘以 2,下一个元素乘以 3,依此类推,将其全部添加到累加器中。我觉得在 Scala 中有更好的方法,甚至可以折叠?
“更好”取决于你的目标是什么。简短而清晰?大概
{ 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)
我更喜欢 zipWithIndex ,它更易于阅读:
array.zipWithIndex.map { case (e, i) => e * (i + 1) }.sum
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 在下面的回答(和评论)中指出的那样,如果性能是一个主要问题,那么最好使用显式递归方法。
我不确定我的建议是否是一种更好的方法,因为它更实用(==它会执行得更慢):
(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 只是用它们的索引压缩集合的元素。