【问题标题】:Add two maps in Groovy while summing up values for common keys在 Groovy 中添加两个映射,同时汇总公共键的值
【发布时间】:2012-04-12 18:47:15
【问题描述】:

我在 Groovy [a: 1, b: 2][b:1, c:3] 中有两张地图,我想从它们中创建第三张地图 [a: 1, b: 3, c: 3]。是否有执行此操作的 Groovy 命令?

编辑:请注意,如果键相同,则第三个映射中的值是前两个映射中的值的总和。

谢谢

【问题讨论】:

    标签: dictionary groovy


    【解决方案1】:

    另一种解决方案是:

    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() ]
    }
    

    epidemian's answer为灵感,你也可以写一个处理多张地图的方法

    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 )
    

    【讨论】:

    • 我认为提供一个完整的方法和一个很好的签名,就像你的第二个例子(而不是抛在空中的表达式)确实增加了一点响应的整体质量,因为这是我们应该做的如果我们担心代码质量,请用“真实”代码编写这些东西。 +1 =D
    【解决方案2】:

    这应该适用于任意数量的地图:

    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]
    

    maps.collectMany{ it.entrySet() } 表达式返回映射条目列表,例如 [a=1, b=2, b=1, c=3],然后将每个条目添加到结果中。

    如果您想将所有转换保留在一个表达式中并使其“更具功能性”,另一种选择是首先按键对条目进行分组,然后对值求和,但我认为它的可读性较差:

    def result = maps.collectMany{ it.entrySet() }
        .groupBy{ it.key }
        .collectEntries{[it.key, it.value.sum{ it.value }]}
    

    groupBy 部分返回 [a:[a=1], b:[b=2, b=1], c:[c=3]] 形式的映射,然后 collectEntries 将该映射转换为另一个具有相同 kays 但值中包含列表总和的映射。

    【讨论】:

    • +1 很好地使用了collectMany(启发我写了一个可变参数方法)
    • 酷!我喜欢这种“组合”方法的外观。这完全是题外话和无关紧要,但是,当编写像foo.bar { ... }.baz { ... } 这样的链式调用时,方法名称和闭包的左大括号之间应该有一个空格,而不是在右大括号和下一个点运算符?我觉得写答案的时候看起来很奇怪,所以我删除了第一个空格,但它看起来也不太好......
    • 是的,这是因为如果方法的最后一个参数是闭包,则括号是可选的……有时很难让它看起来不错;-)
    【解决方案3】:

    以下示例演示了将两个映射添加到第三个映射m3

    Map m1 = [ a:1, b:2 ];
    Map m2 = [ b:1, c:3 ];
    Map m3 = [:];
    m3 << m1
    m3 << m2
    

    【讨论】:

    • 似乎没有阅读问题就回答了。如果键是映射,他想从两个映射中添加价值。它没有回答问题
    • 标题这么乱也不能怪他!
    【解决方案4】:

    一个很好的方法是使用扩展运算符:

    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"
    

    *信用:http://mrhaki.blogspot.ch/2009/09/groovy-goodness-spread-operator.html

    上面的代码在 groovysh 中不起作用,但在 groovy 控制台中很好。 (适用于 1.8 版)

    【讨论】:

    • 抱歉,我没有注意到他想在地图的值中应用总和。
    【解决方案5】:

    我认为没有现成的方法,也许使用类似的方法:

    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 
    }
    

    【讨论】:

      【解决方案6】:

      这样做:

      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
      

      【讨论】:

        【解决方案7】:
        def merge(map1, map2) { 
            def add = { map, entry -> map << entry }
            map2.inject(map1.inject([:], add), add)
        }
        

        【讨论】:

        • 这没有回答问题。丢失键 a 并且不从两个映射中为键 b 添加值
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-06
        • 1970-01-01
        相关资源
        最近更新 更多