public
Created

mapValues on innermost map

  • Download Gist
SalesRow.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
// http://stackoverflow.com/questions/5846208/mapvalues-on-innermost-map-of-nested-maps
 
case class SalesRow(val month:Int, val country:String,
val person:String, val amount:Float)
 
object Test {
def main(args:Array[String] = null) {
val list = new collection.mutable.ListBuffer[SalesRow]()
for (m <- 1 to 12; p <- List("Joe", "Bill")) {
val i = 2 * (if (p == "Joe") 7 else 13)
list += SalesRow(m, "US", p, i.toFloat + (m.toFloat / 100))
}
for (m <- 1 to 12; p <- List("Jean", "Pierre")) {
val i = 3 * (if (p == "Jean") 11 else 17)
list += SalesRow(m, "FR", p, i.toFloat + (m.toFloat / 100))
}
val seq = list.toSeq
import CanMapInner._
val byCountry = seq.groupBy(_.country)
 
// how to bring these implicits in scope?
// simple base case (no nesting involved).
implicit def getSimpleMapper[V,B] = new CanMapInner[V,B,V,B] {
def mapInner(in: V, f: (V) => B): B = f(in)
}
 
// drill down one level of "Map".
implicit def wrappedMapper[K,V,B,InnerV,InnerB](implicit innerMapper: CanMapInner[InnerV,InnerB,V,B]) =
new CanMapInner[Map[K,InnerV], Map[K,InnerB],V,B] {
def mapInner(in: Map[K, InnerV], f: (V) => B): Map[K, InnerB] =
in.mapValues(innerMapper.mapInner(_, f))
}
val byCountryByMonth = deepMapValues(byCountry, (seq:Seq[SalesRow]) => seq.groupBy(_.month))
println(byCountryByMonth)
}
}
 
// adapter from qmajor:
// http://stackoverflow.com/questions/5846208/mapvalues-on-innermost-map-of-nested-maps/5846633#5846633
// trait to tell us how to map inside of a container.
trait CanMapInner[WrappedV, WrappedB,V,B] {
def mapInner(in: WrappedV, f: V => B): WrappedB
}
 
object CanMapInner {
// the actual implementation.
def deepMapValues[K,V,B,WrappedV,WrappedB](map: Map[K,WrappedV], f: V => B)
(implicit mapper: CanMapInner[WrappedV,WrappedB,V,B]) = {
map.mapValues(inner => mapper.mapInner(inner, f))
}
}
 
// vim: set ts=2 sw=2 et:

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.