In detail, I want the key of Map to be the date and time, and the value to be Map(person's name -> the maximum value taken by that person on that date and time). How can I do this?
val d = Map(2020-01-30 -> Seq(Map("fff" -> 177), Map("fsdzf" -> 219), Map("fff" -> 300), Map("fff" -> 0)), 2020-01-26 -> Seq(Map("fvcfdf" -> 188), Map("vav" -> 273)))
TI want the code above to look like the code below.
Map(2020-01-30 -> Map(fff -> 300, fsdzf -> 219), 2020-01-26 -> Map(fvcfdf -> 188, vav -> 273))
CodePudding user response:
Basically you would want the "values"
(mapValues) of your outer Map
, which is a list of some maps, to be aggregated into a single Map (folding):
d.mapValues { listOfInnerMaps =>
listOfInnerMaps.foldLeft(Map.empty[String, Int])(_ _)
}
// or a shorter version of the above thing:
d.mapValues(_.foldLeft(Map.empty[String, Int])(_ _))
If you're sure that the Lists are always non-empty, you can also use reduce (which I would not recommend):
d.mapValues(listOfInnerMaps => listOfInnerMaps.reduce(_ _))
// or a shorter version of the above thing:
d.mapValues(_.reduce(_ _))
Update
So if you want the max value of each inner map, I would suggest you to iterate over the list, and update an accumulator of Map[String, Int]
only if the new value is bigger than the old value:
d.mapValues { listOfMaps =>
listOfMaps.foldLeft(Map.empty[String, Int]) {
case (acc, newMap) =>
newMap.foldLeft(acc) {
case (updatingAcc, (key, value)) =>
updatingAcc.updatedWith(key) {
case Some(oldValue) if value > oldValue => Some(value)
case None => Some(value)
case other => other
}
}
}
}.toMap
CodePudding user response:
Something like this should work:
originalMap
.view
.mapValues(_.flatten)
.mapValues(_.groupMapReduce(_._1)(_._2)(_ max _))
.toMap
Basically, get rid of inner maps first (turn values of outer map into lists of tuples), then group those tuples by first element, and for each group select max of the second.