【问题标题】:Recursive merge nested Map in ScalaScala中的递归合并嵌套映射
【发布时间】:2014-04-29 09:15:54
【问题描述】:

我有一些嵌套地图,例如:

val map1 = Map("key1"->1, "key2"->Map("x"->List(1,2)))
val map2 = Map("key3"->3, "key2"->Map("y"->List(3,4)))

我想将它们合并以获得类似的结果图;

val res = Map("key1"->1, "key2"->Map("x"->List(1,2), "y"->List(3,4)), "key3"->3)

所以嵌套地图也应该合并。 映射和嵌套映射的类型可以假定为 Map[String, Any]。如果两个映射有冲突的键(例如,同一个键的值不同,除了值是嵌套映射),则视为例外。

有什么优雅的解决方案吗? 谢谢!

【问题讨论】:

  • 如果同一个键(如示例中的“key2”)指向一个不是映射的值怎么办?例如。 map1 中的 key1 -> 1 和 map2 中的 key1 -> 2。如果一个值是地图而另一个不是呢?顺便说一句,你这里有一股代码(不好的)气味
  • 这个数据结构,嗯……丑哦。我找不到合适的解决方案。我会尝试使用 foldLeft,但在更高的地图中使用 Int 和 Map 作为值...
  • 其实那是一些反序列化的 json 文档。

标签: scala map


【解决方案1】:
type MapType = Map[String, Any]

def merge(map1 : MapType, map2 : MapType) = (map1.keySet ++ map2.keySet)
  .map(key => key -> mergeValues(map1.get(key), map2.get(key)))
  .toMap

private def mergeValues(o1 : Option[Any], o2 : Option[Any]) = (o1, o2) match {
  case (Some(v1), Some(v2)) => merge(v1.asInstanceOf[MapType], v2.asInstanceOf[MapType])
  case _ => (o1 orElse o2).get
}

norbert-radyk 的改进版本:

  • darkjh 建议的多嵌套级别支持
  • Scala 2.11 兼容性以避免此错误:non-variable type argument String in type pattern scala.collection.immutable.Map[String,Any] (the underlying of MapType) is unchecked since it is eliminated by erasure case (Some(v1 : MapType), Some(v2 : MapType)) => v1 ++ v2

【讨论】:

    【解决方案2】:

    以下内容如何:

    type MapType = Map[String, Any]
    
    def merge(map1 : MapType, map2 : MapType) = (map1.keySet ++ map2.keySet)
      .map(key => key -> mergeValues(map1.get(key), map2.get(key)))
      .toMap
    
    private def mergeValues(o1 : Option[Any], o2 : Option[Any]) = (o1, o2) match {
      case (Some(v1 : MapType), Some(v2 : MapType)) => v1 ++ v2
      case _ => (o1 orElse o2).get
    }
    

    您可以修改mergeValues 函数以支持其他情况(即相同键指向两个不是映射的值的情况 - 目前将返回第一个值)。

    【讨论】:

    • 你可以让mergeValues成为合并函数中的一个函数
    • 同意,它甚至可以内联在map 中,尽管如果添加一些更复杂的案例,可以访问它以便轻松测试mergeValues 函数本身。
    • 谢谢!但是我将v1 ++ v2 更改为merge(v1, v2),以便它支持多级嵌套地图。
    猜你喜欢
    • 1970-01-01
    • 2016-08-12
    • 2015-10-02
    • 1970-01-01
    • 2016-09-24
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多