Consider this class:
case class Person(val firstName: String, val lastName: String, age: Int)
val persons = Person("Jane", "Doe", 42) :: Person("John", "Doe", 45) ::
Person("Joe", "Doe", 43) :: Person("Doug", "Don", 65) ::
Person("Darius", "Don", 24) :: Person("Dora", "Don", 20) ::
Person("Dane", "Dons", 29) :: Nil
To get the sum of the age of all persons, I can write code like:
persons.foldLeft(0)(_ + _.age)
But if I want to use sum
, I need to map the value first and the code looks like this:
persons.map(_.age).sum
How can I use the sum
method without creating some intermediate collection?
(I know that such an "optimization" most probably doesn't have any real performance difference when not run in a tight loop and I also know about lazy views and so on.)
Is it possible to have code like
persons.sum(_.age)
doing what foldLeft
/reduceLeft
does?
You answered is yourself. Just use view
:
persons.view.map(_.age).sum
To convince yourself by examining the workflow:
persons.view.map { p =>
println("invoking age")
p.age
}.map { x =>
println("modifing age")
x + 0
}.sum
Vs:
persons.map { p =>
println("invoking age")
p.age
}.map { x =>
println("modifing age")
x + 0
}.sum
The method sum
in the library doesn't work this way, but you could write your own which does:
def mySum[T, Res](f: T => Res, seq: TraversableOnce[T])(implicit num: Numeric[Res]) =
seq.foldLeft(num.zero)((acc, b) => num.plus(acc, f(b)))
You could also add an implicit conversion so you can call it like seq.sum(f)
instead of mySum(f, seq)
(you may need a different name than sum
to avoid conflicts):
case class SumTraversableOnce[T](val seq: TraversableOnce[T]) {
def sum[Res](f: T => Res)(implicit num: Numeric[Res]) = mySum(f, seq)(num)
}
implicit def toSumTraversableOnce[T](seq: TraversableOnce[T]) =
SumTraversableOnce(seq)
or, since Scala 2.10,
implicit class SumTraversableOnce[T](val seq: TraversableOnce[T]) {
def sum[Res](f: T => Res)(implicit num: Numeric[Res]) = mySum(f, seq)(num)
}
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