blue-sky
blue-sky

Reputation: 53826

Averaging values in List contained in Map

Here is code I wrote to average coordinate values contained within the values of a Map :

 val averaged = Map((2,10) -> List((2.0,11.0), (5.0,8.0)))
                                                  //> averaged  : scala.collection.immutable.Map[(Int, Int),List[(Double, Double)
                                                  //| ]] = Map((2,10) -> List((2.0,11.0), (5.0,8.0)))
 averaged.mapValues(m => {


    val s1 = m.map(m => m._1).sum
    val s2 = m.map(m => m._2).sum

  (s1 / m.size , s2 / m.size)
 })                                               //> res0: scala.collection.immutable.Map[(Int, Int),(Double, Double)] = Map((2,
                                                  //| 10) -> (3.5,9.5))

This code works as expected but the mapValues function requires number of passes equals to length of the List. Is there a more idiomatic method of achieving same using Scala ?

Upvotes: 2

Views: 64

Answers (1)

dhg
dhg

Reputation: 52681

If I'm understanding your question correctly, you are asking if it is possible to avoid the traversal of m on each access. The mapValues method returns a view of a Map, meaning that there will be repeated work on access. To avoid that, just use map instead:

val averaged = Map((2, 10) -> List((2.0, 11.0), (5.0, 8.0)))
val result = averaged.map { 
  case (key, m) =>
    val (s1, s2) = m.unzip
    (s1.sum / m.size, s2.sum / m.size)
}
println(result)
// Map((2,10) -> (3.5,9.5))

Using unzip additionally means that the code won't traverse m more than once.

Upvotes: 1

Related Questions