I have a file containing data on Salesman, Product, Location, SalesValue
For instance:
Bob, Carrots, United States, 200
Bill, Potatoes, England, 100
Bob, Oranges, England, 50
Bob, Carrots, United States, 20
The SalesValue can be succinctly accumulated into a hash of hash of hash in perl using the following code
while(<>){
@cols = split(/,/);
$vals {$cols[0]} {$cols[1]} {$cols[2]} += $cols[3];
}
Has anyone got any suggestions how this creation of a map of map of map, plus the accumulation , could best be implemented in scala?
I would suggest to see the merging of these maps as a monoid-append
operation.
First we create the maps of maps of maps as single elements:
val input = """Bob, Carrots, United States, 200
|Bill, Potatoes, England, 100
|Bob, Oranges, England, 50
|Bob, Carrots, United States, 20""".stripMargin.lines.toList
val mmm = input.map(_.split(", "))
.map { case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) }
mmm
is of type List[Map[String, Map[String, Map[String, Int]]]]
:
List[Map[String,
Map[String,
Map[String, Int]]]]
Then we could suml
using a library like scalaz
or cats
:
import scalaz._, Scalaz._
println(mmm.suml)
This will print (not idented):
Map(Bill -> Map(Potatoes -> Map(England -> 100)),
Bob -> Map(Oranges -> Map(England -> 50),
Carrots -> Map(United States -> 220)))
To help understand what is happening behind the .suml
operation I would shamelessly suggest to checkout this presentation I made last year https://speakerdeck.com/filippovitale/will-it-blend-scalasyd-february-2015
EDIT
We can also see our maps of maps of maps as Foldable
and use foldMap
for the same result:
input.map(_.split(", "))
.foldMap{ case Array(n, g, c, v) => Map(n -> Map(g -> Map(c -> v.toInt))) }
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