Given the following list of maps (list could be longer):
List(
Map[String,String]("wind"->"none", "rain"->"none", "class"->"on time"),
Map[String,String]("wind"->"none", "rain"->"slight", "class"->"on time"),
Map[String,String]("wind"->"none", "rain"->"slight", "class"->"late"),
...
)
How can I group the maps that I have something like this:
"on time" -> ("wind"->"none", "rain"->"none", "wind"->"none", "rain"->"slight")
"late" -> ("wind"->"none", "rain"->"slight")
I get stuck at working on several maps.
CodePudding user response:
Another option:
val maps =
List(
Map[String, String]("wind" -> "none", "rain" -> "none", "class" -> "on time"),
Map[String, String]("wind" -> "none", "rain" -> "slight", "class" -> "on time"),
Map[String, String]("wind" -> "none", "rain" -> "slight", "class" -> "late"),
Map[String, String]("wind" -> "none", "rain" -> "slight")
)
val grouped = maps.foldLeft(Map.empty[String, List[(String, String)]]) {
case (acc, map) if map.contains("class") =>
val key = map("class")
if (acc.contains(key))
acc.updated(key, acc(key) (map - "class").toList)
else
acc (key -> (map - "class").toList)
case (acc, _) => acc
}
CodePudding user response:
Here's one way to go about it. (Scala 2.13.x)
val maps = List(...)
val rslt = maps.groupMap(_("class"))(_ - "class")
.map{case (k,v) => k -> v.flatten}
I know the map()
call can be simplified to a mapValues()
but that's been deprecated in 2.13 so I don't use it.
This will, of course, throw at runtime if there are any Map
elements in the List
without a "class"
key.
CodePudding user response:
In vanilla Scala 2.12\2.11
assuming the starting point:
val maps =
List(
Map[String, String]("wind" -> "none", "rain" -> "none", "class" -> "on time"),
Map[String, String]("wind" -> "none", "rain" -> "slight", "class" -> "on time"),
Map[String, String]("wind" -> "none", "rain" -> "slight", "class" -> "late")
)
you could fold everything:
maps
.filter(_.contains("class")) // guarantee "class" key exists
.map(m => m("class") -> (m - "class").toList)
.foldLeft(Map.empty[String, List[(String, String)]]) {
case (acc, (key, values)) if acc.contains(key) =>
acc.updated(key, acc(key) values)
case (acc, (key, values)) =>
acc ((key, values))
}
This logic is safe with any input as it will filter out Map[_,_]
without class
key.
You could remove that .map(..)
and do everything in one go in the fold
.
If you can guarantee the input is non-empty and contains key class
you could use reduceLeft
instead of foldLeft
and drop the filter
.
Bonus the logic is compatible with Iterator[_]
:
maps
.iterator
.filter(..)
.map(..)
.foldLeft(..)(..)
}