Reputation: 684
I would like to know if someone have an easy way to merge 2 deep nested maps together ?
For instance, I would like to get :
[
"a" : "1",
"animals" : ["cat" : "blue"]
] + [
"b" : 2,
"animals" : ["dog" : "red"]
] == [
"a" : 1,
"b" : 2,
"animals" : [
"cat" : "blue",
"dog" : "red"]
]
There is someone having easy solution ?
Upvotes: 18
Views: 7248
Reputation: 490
I usually use ConfigObject for this. It does deep merge along other goodies.
a= [
"a" : "1",
"animals" : ["cat" : "blue"]
]
b= [
"b" : 2,
"animals" : ["dog" : "red"]
]
result = (HashMap)new ConfigObject(a).merge(((ConfigObject)b))
Upvotes: 0
Reputation: 2146
Another solution similar to @dmahapatro, but without using metaClass:
Map mergeMaps(Map lhs, Map rhs) {
rhs.each { k, v ->
lhs[k] = (lhs[k] in Map ? mergeMaps(lhs[k], v) : v)
}
return lhs
}
def m1 = [a: 1, animals: [cat: 'blue']]
def m2 = [b: 2, animals: [dog: 'red']]
mergeMaps(m1, m2)
println(m1)
Upvotes: 1
Reputation: 7867
This is a very short, concise way of doing it without using the meta-programming:
Map one = ["a" : "1", "animals" : ["cat" : "blue"] ]
Map two = ["b" : "2", "animals" : ["dog" : "red"] ]
Map three = [:]
(one.entrySet() + two.entrySet()).each { entry ->
three[entry.key] = three.containsKey(entry.key) ? [:] << three[entry.key] << entry.value : entry.value
}
println three
Renders the output:
[a:1, animals:[cat:blue, dog:red], b:2]
Upvotes: 0
Reputation: 50245
You can write one for Map
using recursion:
Map.metaClass.addNested = { Map rhs ->
def lhs = delegate
rhs.each { k, v -> lhs[k] = lhs[k] in Map ? lhs[k].addNested(v) : v }
lhs
}
def map1 = [
"a" : "1",
"animals" : ["cat" : "blue"]
]
def map2 = [
"b" : 2,
"animals" : ["dog" : "red"]
]
assert map1.addNested( map2 ) == [
a: '1',
animals: [cat: 'blue', dog: 'red'],
b: 2
]
Upvotes: 20
Reputation: 8119
I had a similar solution as @dmahapatro, but with a method with variable arguments:
def m1 = [a: 1, animals: [cat: 'blue']]
def m2 = [b: 2, animals: [dog: 'red']]
Map merge(Map... maps) {
Map result
if (maps.length == 0) {
result = [:]
} else if (maps.length == 1) {
result = maps[0]
} else {
result = [:]
maps.each { map ->
map.each { k, v ->
result[k] = result[k] instanceof Map ? merge(result[k], v) : v
}
}
}
result
}
assert [:] == merge()
assert m1 == merge(m1)
assert [a:1, b:2, animals:[cat:'blue', dog:'red']] == merge(m1, m2)
Upvotes: 12