代码之家  ›  专栏  ›  技术社区  ›  St.Antario

可变地图深合并

  •  0
  • St.Antario  · 技术社区  · 4 年前

    有没有一种简洁的方法可以在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)))
    

    三。

    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] )合并。

    0 回复  |  直到 4 年前
        1
  •  3
  •   Krzysztof Atłasik    4 年前

    你所描述的实际上是 cats.Semigroup . 所以你可以用联合收割机( |+|

    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 ,但可以从一个for immutable派生:

    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
  •  1
  •   jwvh    4 年前

    这也许可以。

    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