问题
I have some nested maps like:
val map1 = Map("key1"->1, "key2"->Map("x"->List(1,2)))
val map2 = Map("key3"->3, "key2"->Map("y"->List(3,4)))
And I want to merge them to obtain the result map like;
val res = Map("key1"->1, "key2"->Map("x"->List(1,2), "y"->List(3,4)), "key3"->3)
So nested maps should also be merged. The type of the maps and nested maps can be assumed as Map[String, Any]. It's considered an exception if the two maps have conflict keys (eg. values of the same key are different, except that the value is a nested map).
Is there some elegant solution to this? Thanks!
回答1:
How about the following:
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
}
You can modify the mergeValues
function to support additional cases (i.e. situation when the same key points to 2 values which are not maps - at the moment will return the first of the values).
回答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), Some(v2)) => merge(v1.asInstanceOf[MapType], v2.asInstanceOf[MapType])
case _ => (o1 orElse o2).get
}
Improved version of norbert-radyk with :
- Multiple nested level support suggested by darkjh
- Scala 2.11 compatibility to avoid this error :
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
来源:https://stackoverflow.com/questions/23360468/recursive-merge-nested-map-in-scala