首页 > 解决方案 > Scala:如何对 Map[String, List[(String, Map[Long, Int])]] 中的 mapValues 求和

问题描述

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

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。我该如何解决这个问题?谢谢!

标签: scala

解决方案


如果您需要减少内部映射中的值,您可以使用 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))

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

更新:如果你可以使用库,你可以做更简单的只使用猫组类型类:

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

推荐阅读