Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala: accumulate a var from collection in a functional manner (that is, no vars)

this is a newbie question

I have the following code:

var total = 0L
docs.foreach(total += _.length)

in docs I have a collection of objects with the .length property

I'd like something like:

val total = docs.[someScalaMethod](0, (element, acum) => acum + element.length )

I mean, a method that iterates each element passing an accumulator variable...

The first zero I pass should be the initial value of the accumulator var..

How can it be achieved?

like image 442
opensas Avatar asked Dec 04 '11 13:12

opensas


3 Answers

This called a fold. It's almost exactly what you stated:

docs.foldLeft(0)((accum, element) => accum + element.length)

for the version that traverses the collection from left to right (usually preferable; right to left is foldRight, and 2.9 has a fold that can start anywhere, but has limitations on how it can transform the type).

Once you get used to this, there is a short-hand version of fold left, where the accumulator goes on the left (think of it being pushed from left to right through the list), and you use placeholders for the variable names since you only use them once each: (0 /: docs)(_ + _.length)

like image 93
Rex Kerr Avatar answered Oct 17 '22 23:10

Rex Kerr


docs map { _.length } reduce { _ + _ }

or (the thx goes to Luigi Plinge)

docs.map(_.length).sum
like image 44
agilesteel Avatar answered Oct 18 '22 00:10

agilesteel


Here is a Scalaz version:

docs.foldMap(_.length)

This is equivalent to docs.map(_.length).sum but takes only one pass. Also, works with all monoids.

like image 4
missingfaktor Avatar answered Oct 17 '22 23:10

missingfaktor