Scala嵌套映射合并

Scala嵌套映射合并,scala,scala-collections,Scala,Scala Collections,我想合并嵌套贴图,但我不知道如何合并内部贴图 var a = Map[String,Map[String,String]]() a = a + ("key1" -> Map("subkey1" -> "a")) a = a + ("key1" -> Map("subkey2" -> "b")) a = a + ("key2" -> Map("subkey1" -> "c")) 我希望合并所有这些,以便得到以下结果: Map("key1" -> Map(

我想合并嵌套贴图,但我不知道如何合并内部贴图

var a = Map[String,Map[String,String]]()
a = a + ("key1" -> Map("subkey1" -> "a"))
a = a + ("key1" -> Map("subkey2" -> "b"))
a = a + ("key2" -> Map("subkey1" -> "c"))
我希望合并所有这些,以便得到以下结果:

Map("key1" -> Map("subkey1" -> "a", "subkey2" -> "b"), "key2" -> Map("subkey1" -> "c"))

这有什么标准方法吗

内置的任何东西都不能很好地实现此功能,但是
getOrElse
是您的朋友。如果您确定没有子映射集合,那么逻辑的核心如下

val x = a.getOrElse(key, mutable.Map.empty[String,String])
a = a + (key -> (x ++ subMap))

如果可能发生冲突,则需要执行除
++
以外的操作--可能再次使用相同的技巧获取子键并更新其值(如果存在)。

似乎没有为此提供直接方法。您可以提供一个助手方法

def mergeUpdate[K1, K2, V](base: Map[K1, Map[K2, V]], tuple: (K1, Map[K2, V])) = {
  base + (tuple._1 -> (base.getOrElse(tuple._1, Map.empty) ++ tuple._2))
}
然后重写代码:

var a = Map[String,Map[String,String]]()
a = mergeUpdate(a, ("key1" -> Map("subkey1" -> "a")))
a = mergeUpdate(a, ("key1" -> Map("subkey2" -> "b")))
a = mergeUpdate(a, ("key2" -> Map("subkey1" -> "c")))

// =>
a: scala.collection.immutable.Map[String,Map[String,String]] = Map(key1 -> Map(subkey1 -> a, subkey2 -> b), key2 -> Map(subkey1 -> c))

如果可以使用Scalaz-可能会有帮助:

import scalaz._, Scalaz._
val map1 = Map("key1" -> Map("subkey1" -> "a"))
val map2 = Map("key1" -> Map("subkey2" -> "b"))
val map3 = Map("key2" -> Map("subkey1" -> "c"))

scala> map1 |+| map2 |+| map3
res0: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]] = 
   Map(key2 -> Map(subkey1 -> c), key1 -> Map(subkey2 -> b, subkey1 -> a))
唯一的限制-您的值应已定义,以便处理冲突:

trait A
object A1 extends A
object A2 extends A 

implicit val ASemigroup = new Semigroup[A] {
  def append(a: A, b: => A) : A = a //"choose first" strategy
}

val map1 = Map("key1" -> Map("subkey1" -> (A1: A)))
val map2 = Map("key1" -> Map("subkey1" -> (A2: A)))

scala> map1 |+| map2
res8: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,A]] = 
   Map(key1 -> Map(subkey1 -> A1$@2cb79bd1))

顺便说一句,字符串上已经定义了半组,所以冲突将导致字符串的连接。

如果您可以提取其他依赖项,您可以尝试此方法

scala> import com.daodecode.scalax.collection.extensions._
import com.daodecode.scalax.collection.extensions._

scala> val m1 = "key1" -> Map("subkey1" -> "a")
m1: (String, scala.collection.immutable.Map[String,String]) = (key1,Map(subkey1 -> a))

scala> val m2 = "key1" -> Map("subkey2" -> "b")
m2: (String, scala.collection.immutable.Map[String,String]) = (key1,Map(subkey2 -> b))

scala> val m3 = "key2" -> Map("subkey1" -> "c")
m3: (String, scala.collection.immutable.Map[String,String]) = (key2,Map(subkey1 -> c))

scala> Seq(m1, m2, m3).toCompleteMap.
  mapValues(_.foldLeft(Map.empty[String,String]){ 
    case (acc, m) => acc.mergedWith(m)(_ + _)})
res0: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,String]] = Map(key2 -> Map(subkey1 -> c), key1 -> Map(subkey1 -> a, subkey2 -> b))
和是方法的扩展。它已发布到maven central


(+)
这是您自己的冲突解决功能

如果子贴图中的关键点之间发生冲突怎么办?类似于
key1
映射下的两个
subkey1
。@m-z理想情况下,碰撞可以由2-arity函数处理。在我的例子中,签名更像是Map[String,Map[String,Seq[String]]],然后将值加在一起。