【问题标题】:mutable.Map deep mergemutable.Map 深度合并
【发布时间】:2021-03-13 01:53:12
【问题描述】:

有没有一种简洁的方法可以在 Scala 中深度合并两个可变映射?

case class K1(i: Int)
case class K2(i: Int)

def deepMerge(map: mutable.Map[K1, Map[K2, List[Int]]],
              mergee: mutable.Map[K1, Map[K2, List[Int]]]
): Unit = ???

例子:

我。

val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> Map(K2(1) -> List(2)))

deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1, 2)))

二。

val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> Map(K2(2) -> List(1)))

deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1), K2(2) -> List(1)))

III.

val map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(2) -> Map(K2(2) -> List(1)))

deepMerge(map, mergee)
map = mutable.Map(K1(1) -> Map(K2(1) -> List(1)), K1(2) -> Map(K2(2) -> List(1)))

即如果两个映射中存在相同的键,则键对应的值 (List[Int]) 将被合并。

有没有办法简洁地实现它,避免大量检查特定键是否出现在另一个地图中?使用像scalaz或cats这样的FP库也可以。

【问题讨论】:

标签: scala dictionary collections scalaz scala-cats


【解决方案1】:

我正在使用猫添加另一个答案。

您所描述的实际上是cats.Semigroup 的行为。所以你可以使用 combine (|+|) 运算符来深度合并地图:

import cats.implicits._
import cats._

case class K1(i: Int)
case class K2(i: Int)

val map = Map(K1(1) -> Map(K2(1) -> List(1)))
val mergee = Map(K1(1) -> Map(K2(1) -> List(2)))

val deepMerged = map |+| mergee

println(deepMerged) // HashMap(K1(1) -> HashMap(K2(1) -> List(1, 2)))

问题是猫库没有为 mutable.Map 提供 Semigroup 的实例,但您可以从一个不可变的实例派生它:

import cats.implicits._
import scala.collection.immutable
import scala.collection.mutable
import cats._

//here I derivive Semigroup instance for mutable.Map from instance for immutable.Map
implicit def mutableMapSemigroup[K, V: Semigroup]: Semigroup[mutable.Map[K, V]] = Semigroup[immutable.Map[K, V]].imap(c => mutable.Map.from(c))(c => immutable.Map.from(c))

case class K1(i: Int)
case class K2(i: Int)

val map = mutable.Map(K1(1) -> mutable.Map(K2(1) -> List(1)))
val mergee = mutable.Map(K1(1) -> mutable.Map(K2(1) -> List(2)))

println(map |+| mergee)

但请记住,这实际上是将可变映射转换为不可变映射,然后进行合并,然后再转换回可变映射,因此它可能效率不高。

【讨论】:

    【解决方案2】:

    这可能会做到。

    def deepMerge(mergeA: Map[K1, Map[K2, List[Int]]],
                  mergeB: Map[K1, Map[K2, List[Int]]]
                 ): Map[K1,Map[K2,List[Int]]] =
      (mergeA.toList ++ mergeB.toList).groupMap(_._1)(_._2).map{
        case (k1,ms) =>
          k1 -> ms.flatMap(_.toList).groupMap(_._1)(_._2).map{
            case (k2,ls) => k2 -> ls.flatten
          }
        }
    

    我还没有使用mutable Maps 对其进行测试,但它的工作原理应该差不多。

    【讨论】:

      猜你喜欢
      • 2021-04-18
      • 1970-01-01
      • 2015-05-05
      • 1970-01-01
      • 1970-01-01
      • 2015-03-12
      相关资源
      最近更新 更多