I have two maps in Groovy [a: 1, b: 2]
and [b:1, c:3]
and would like to create from them a third map [a: 1, b: 3, c: 3]
. Is there a Gr
I don't think there's a ready-made method for this, maybe use something like:
def m1 = [a: 1, b: 2]
def m2 = [b: 1, c: 3]
def newMap = (m1.keySet() + m2.keySet()).inject([:]) {
acc, k -> acc[k] = (m1[k] ?: 0) + (m2[k] ?: 0); acc
}
The following example demonstrates adding two maps, to a third map m3
:
Map m1 = [ a:1, b:2 ];
Map m2 = [ b:1, c:3 ];
Map m3 = [:];
m3 << m1
m3 << m2
This should work for any number of maps:
def maps = [[a: 1, b: 2], [b:1, c:3]]
def result = [:].withDefault{0}
maps.collectMany{ it.entrySet() }.each{ result[it.key] += it.value }
assert result == [a: 1, b: 3, c: 3]
The maps.collectMany{ it.entrySet() }
expression returns a list of map entries, like [a=1, b=2, b=1, c=3]
, and then each of those is added to the result.
Another option, if you'd like to keep all the transformation into one expression and make it "more functional", is to first group the entries by key and then sum the values, but I think it's less readable:
def result = maps.collectMany{ it.entrySet() }
.groupBy{ it.key }
.collectEntries{[it.key, it.value.sum{ it.value }]}
The groupBy
part returns a map of the form [a:[a=1], b:[b=2, b=1], c:[c=3]]
and then the collectEntries
transforms that map into another one that has the same kays but has the sum of the lists in the values instead.
A nice way is it use the spread operator:
def m1 = [ a:1, b:2 ]
def m2 = [ b:1, c:3 ]
def m3 = [ *:m1, *:m2 ]
println "m1 = $m1"
println "m2 = $m2"
println "m3 = $m3"
*Credit:http://mrhaki.blogspot.ch/2009/09/groovy-goodness-spread-operator.html
The code above does not work in groovysh but it is fine in the groovy console. (for version 1.8)
Yet another solution would be:
def m1 = [ a:1, b:2 ]
def m2 = [ b:1, c:3 ]
def newMap = [m1,m2]*.keySet().flatten().unique().collectEntries {
[ (it): [m1,m2]*.get( it ).findAll().sum() ]
}
Taking epidemian's answer as inspiriation, you can also write a method to handle multiple maps
def m1 = [a: 1, b: 2]
def m2 = [b: 1, c: 3]
def combine( Map... m ) {
m.collectMany { it.entrySet() }.inject( [:] ) { result, e ->
result << [ (e.key):e.value + ( result[ e.key ] ?: 0 ) ]
}
}
def newMap = combine( m1, m2 )
This does it:
Map additionJoin( Map map1, Map map2 )
{
def result = [:];
result.putAll( map1 );
result.putAll( map2 );
result.each { key, value ->
if( map1[key] && map2[key] )
{
result[key] = map1[key] + map2[key]
}
}
return result;
}
def a = [a: 1, b: 2]
def b = [b:1,c:3]
def c = additionJoin( a, b )
println c