Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to score and sum in Scala?

Tags:

scala

sum

Is there a better way of doing this:

val totalScore = set.foldLeft(0)( _ + score(_) )

or this:

val totalScore = set.toSeq.map(score(_)).sum

I think it's quite a common operation so was expecting something sleeker like:

val totalScore = set.sum( score(_) )
like image 986
adam77 Avatar asked May 21 '10 04:05

adam77


3 Answers

Well, there are alternative ways to write it:

val totalScore = set.toSeq.map(score(_)).sum
val totalScore = set.toSeq.map(score).sum
val totalScore = set.toSeq map score sum

The last one may require a semi-colon at the end if the next line doesn't start with a keyword. One can also use .view instead of .toSeq, which would avoid allocating a temporary collection. However, I'm not sure the .view's present behavior (of showing repeated elements) is the correct one.

like image 77
Daniel C. Sobral Avatar answered Nov 05 '22 00:11

Daniel C. Sobral


Seq.sum does not take a function which could be used to score the sum. You could define an implicit conversion which "pimps" Traversable:

implicit def traversableWithSum[A](t: Traversable[A])(implicit m: Numeric[A]) = new {
  def sumWith(f: A => A) = t.foldLeft(m.zero)((a, b) => m.plus(a, f(b)))
}

def score(i: Int) = i + 1

val s = Set(1, 2, 3)

val totalScore = s.sumWith(score _)
println(totalScore)
=> 9

Please note that the Numeric trait only exists in Scala 2.8.

like image 22
Michel Krämer Avatar answered Nov 05 '22 00:11

Michel Krämer


Alternately, the Seq#sum overload that takes an implicit conversion to Numeric could be used if the type in the collection to be scored / summed does not itself have an addition operator. However, because it's an implicit conversion parameter, it won't be applied unless required to make the reduce closure type-check.

like image 1
Randall Schulz Avatar answered Nov 04 '22 22:11

Randall Schulz