Scala: Как суммировать значения mapValues ​​в Map [String, List [(String, Map [Long, Int])]]] - PullRequest
0 голосов
/ 08 февраля 2020

Это сложная структура, например:

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. Как это исправить? Спасибо!

Ответы [ 3 ]

0 голосов
/ 08 февраля 2020

Если вам нужно уменьшить свои значения на внутренней карте, вы можете использовать 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))

, но помните, что таким образом вы потеряете ключи внешней карты и строковые значения в списке (элемент жажды) в списке пар).

ОБНОВЛЕНИЕ: Если вы можете использовать библиотеку cats , вы можете сделать это проще, просто используя тип кошки полугруппа :

import cats.implicits._
val res = testMap.mapValues(_.map(_._2).reduce(_ |+| _))
0 голосов
/ 08 февраля 2020

Расширение по вашему собственному решению:

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 
})))
0 голосов
/ 08 февраля 2020

вы можете попробовать что-то вроде этого, я знаю, это выглядит немного сложнее, но я пытался охватить какой-то угловой случай, чтобы сделать код более динамичным c

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)))
              }
          }
      }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...