Scala嵌套地图合并

时间:2015-04-12 00:08:51

标签: 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("subkey1" -> "a", "subkey2" -> "b"), "key2" -> Map("subkey1" -> "c"))

这有什么标准方法吗?

4 个答案:

答案 0 :(得分:1)

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

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))

唯一限制 - 您的值应定义Semigroup以便处理冲突:

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))

顺便说一下,字符串已经在它们上定义了Semigroup,因此碰撞会导致字符串在那里连接。

答案 1 :(得分:0)

内置的内容并不适用于此,但getOrElse是您的朋友。如果您确定没有子图集合,则逻辑的核心看起来像

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

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

答案 2 :(得分:0)

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

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))

答案 3 :(得分:0)

如果您可以提取其他依赖项,可以试试这个

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))

toCompleteMapmergedWith是来自https://github.com/jozic/scalax-collection的扩展方法。它已发布到maven central

(_ + _)这是您自己的碰撞解决功能