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

前端 未结 7 914
花落未央
花落未央 2020-12-16 12:24

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

相关标签:
7条回答
  • 2020-12-16 12:44

    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 
    }
    
    0 讨论(0)
  • 2020-12-16 12:46

    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
    
    0 讨论(0)
  • 2020-12-16 12:48

    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.

    0 讨论(0)
  • 2020-12-16 12:53

    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)

    0 讨论(0)
  • 2020-12-16 12:55

    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 )
    
    0 讨论(0)
  • 2020-12-16 12:55

    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
    
    0 讨论(0)
提交回复
热议问题