I have Scala code like this
var i = 1
for(e <- array) {
acc += e * i
i += 1
}
I need to multiply the first element in the array by 1, the next by 2, the next by 3 and so on adding it all into an accumulator. I feel that there is a better way of doing this in Scala, maybe even with folding?
"Better" depends on what your goals are. Short and clear? Probably
{ for (i <- array.indices; e = array(i)) yield (i+1)*e }.sum
or
array.indices.map(i => (i+1)*array(i)).sum
(or slightly faster, since you create the intermediates as you go:
array.indices.iterator.map(i => (i+1)*array(i)).sum
).
You should usually be short and clear.
Fast? Then you'll need to go old-school:
var i = 0
var acc = 0
while (i < array.length) {
acc += (i+1)*array(i)
i += 1
}
or use recursion
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)
I prefer zipWithIndex which is simpler to read:
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
In other words, starting with an accumulator of 0 and a multiplier of 1, fold each element of the list in, changing the accumulator to acc + (l * mult)
and incrementing the multiplier by 1. We get the final multiplier out at the end as well, so we call ._1
to just get the accumulator.
Edit: As @RexKerr points in his answer below (and the comment), if performance is a major concern then you're better off using an explicit recursive method.
I am not sure if what I suggest is a better way to do it or not, as it is more functional (== it will perform slower):
(0 /: (array zipWithIndex)) {(a, i) => (i._1 * (i._2 + 1)) + a}
This does perform foldLeft on an array which is produced by zipWithIndex method in http://www.scala-lang.org/api/current/index.html#scala.Array
zipWithIndex simply zips the elements of a collection with their indices.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With