Scala:如何对 Map[String, List[(String, Map[Long, Int] 中的 mapVal



这是一个复杂的结构,例如:

val testMap: Map[String, List[(String, Map[Long, Int])]] = Map(
"test1" ->
List(
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(2222222222L -> 2))
)
)

如何使用相同的键对值求和?我期待结果是:

Map(test1 -> Map(1111111111 -> 8, 2222222222 -> 2))

到目前为止,我尝试的是:

val res = testMap.mapValues(_.map(_._2).reduce(_ ++ _))

但我得到的结果是:

Map(test1 -> Map(1111111111 -> 2, 2222222222 -> 2))

1111111111的值为 2 而不是 8。我该如何解决这个问题?谢谢!

如果您需要减少内部映射中的值,您可以使用 foldLeft 并累积结果映射:

def combineInner(mapA: Map[Long, Int], mapB: Map[Long, Int]): Map[Long, Int] = {
mapA.foldLeft(mapB) {
case (mapWithSum, (key, value)) =>
mapWithSum.updated(key, mapWithSum.getOrElse(key, 0) + value)
}
}
val res = testMap.mapValues(_.map(_._2).reduce(combineInner))

但请记住,您将以这种方式丢失外部映射键和列表中的字符串值(对列表中的 thirst 元素(。

更新: 如果可以使用cats库,则只需使用 cats半组类型类就可以做更简单的事情:

import cats.implicits._
val res = testMap.mapValues(_.map(_._2).reduce(_ |+| _))

你可以尝试这样的东西,我知道它看起来有点复杂,但我试图涵盖一些极端情况以使代码更加动态

testMap.mapValues{values =>
values.groupBy(_._1).flatMap{
case (_ , values) =>
values.foldLeft(Map.empty[Long, Int]){
case (acc, (_, nextMap)) =>
nextMap.flatMap{
case (key, value) =>
acc.get(key).fold(acc + (key -> value))(intValue => acc + (key -> (value + intValue)))
}
}
}
}

扩展您自己的解决方案:

val testMap: Map[String, List[(String, Map[Long, Int])]] = Map(
"test1" ->
List(
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(1111111111L -> 2)),
("test1", Map(2222222222L -> 2))
)
)
val res = testMap.map(t => (t._1, t._2.map(_._2).reduce((map1, map2) => { 
val combinedMap = map1.map { 
case (k, v1) => 
(k, map2.get(k).map(v2 => v1 + v2).getOrElse(v1)) 
}
val uniqueKeyFromMap2 = map2.filterNot(t => map1.contains(t._1))
combinedMap ++ uniqueKeyFromMap2 
})))

相关内容

最新更新