Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add two maps in Groovy while summing up values for common keys

Tags:

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 Groovy command that does that?

Edit: Notice that the values in the third map, are a sum of the values from the first two maps, if the keys are identical.

Thanks

like image 851
user971956 Avatar asked Apr 12 '12 18:04

user971956


People also ask

How do I add multiple maps to Groovy?

The easiest way to merge two maps in Groovy is to use + operator. This method is straightforward - it creates a new map from the left-hand-side and right-hand-side maps.

How do I create a Hashmap in Groovy?

Map Declaration You have two options to declare a map in groovy. First option is, define an empty map and put key-value pairs after. Second option is declaring map with default values.

What is Groovy hash map?

A hashmap maps a key to a value, but you are trying to map a key to two values. To do this, create a hashmap, where the key is your ID and the value is another hashmap, mapping the string "firstname" to "Jack" and the string "lastname" to "Sparrow" and so on for all <person> elements. Morten.


2 Answers

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 )
like image 52
tim_yates Avatar answered Sep 23 '22 15:09

tim_yates


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.

like image 35
epidemian Avatar answered Sep 23 '22 15:09

epidemian