How to merge two maps in groovy

后端 未结 5 1259
予麋鹿
予麋鹿 2021-01-06 02:32

Question:
How to merge the maps while summing up values of common keys among the maps.

Input:

[a: 10, b:2, c:         


        
5条回答
  •  时光说笑
    2021-01-06 02:45

    Below groovy script uses and addresses the OP question using closure. That will help to decide user to choose the merge strategy for the value of each key in the merged map.

    NOTE: The script sample is using 3 maps to make sure the script is able to handle the merging of multiple maps. This solution provided here would scale even if there are more maps to be handled.

    While merging, it is possible that each map may not have all the keys, so it is possible to have null when user tries to get the value. Hence removing null from list that is passed to the Collection.

    /**
     * this script to merge the maps based on the closure provided by user based on different use case
     */
    
     //For sample, taking below 3 maps
    def map1 = [a:10, b:2, c:3]
    def map2 = [b:3, c:2, d:5]
    def map3 = [d:3,a:4,e:9]
    
    //Below method takes list of maps and closure as input and returns merged map
    def getMergedMap(list, closure) {
       def keys = [] as Set
       list.each { element -> keys.addAll(element.keySet()) }
       def map = [:]
       keys.each { k ->
           def items = []
           list.each { items.add(it[k]) }
            map[k] =  closure(items)
        }
       map
    }
    
    //Create the list of maps
    def mapList = [map1, map2, map3]
    //Call the above method and pass the closure are need for merging condition, here min of matched key values from multiple maps
    def newmap = getMergedMap(mapList) { list -> Collections.min(list - null)  }
    println newmap
    //Call the above method and pass the closure are need for merging condition, here max of matched key values from multiple maps
    newmap = getMergedMap(mapList) { list -> Collections.max(list - null)  } 
    println newmap
    //Call the above method and pass the closure are need for merging condition, here sum of matched key values from multiple maps
    newmap = getMergedMap(mapList) { list -> (list-null).sum()  }
    println newmap
    

    Output for the above code:

    [a:4, b:2, c:2, d:3, e:9]
    [a:10, b:3, c:3, d:5, e:9]
    [a:14, b:5, c:5, d:8, e:9]
    

    UPDATE: If you want default behavior while merging, retains value from last map in the order of merging, below closure call can be used

    newmap = getMergedMap(mapList) { list -> (list-null).last()   }
    println newmap
    

    And results to:

    [a:4, b:3, c:2, d:3, e:9]
    

    You may quickly test the script from here Demo

    UPDATE2: The above getMeredMap is simple and readable. Of course, can be groovified / condensed using multiple inject's to as shown below on-liner:

    def getNewMap(list, closure) {
            list.inject([], { klist, map -> klist.addAll(map.keySet()); klist as Set }).inject([:]) { m, k -> m[k] = closure(list.inject([]){ vlist,map -> vlist << map[k] });m }
    }
    

    UPDATE 3
    You may also simplify calling code by defining the closures separately for merged value strategy. That makes little simplify, imo. Also handled null values while merging inside instead of letting user handle outside and this would more clean to those who uses getMergedMap method.

    //Merging of multiple maps with different merge strategies 
    //And handled null inside of mergeMethod instead of outside like earlier
    def map1 = [a:10, b:2, c:3]
    def map2 = [b:3, c:2, d:5]
    def map3 = [d:3, a:4, e:9]
    
    //Input map list and Merge strategy closure and handling null
    def getMergedMap(list, closure) {
       list.inject([],{ klist, map -> klist.addAll(map.keySet());klist as Set}).inject([:]) { m, k -> m[k] =  closure(list.inject([]){ vlist,map -> vlist << map[k];vlist-null });m }
    }
    
    def mapList = [map1, map2, map3]
    
    //Closures for merged value strategy
    def minValue = { list -> Collections.min(list) }
    def maxValue = { list -> Collections.max(list) }
    def totalValue = { list -> list.sum() }
    def defaultValue = { list -> list.last() }
    
    //Call merge maps with strategies and assert
    assert [a:4, b:2, c:2, d:3, e:9] == getMergedMap(mapList, minValue)
    assert [a:10, b:3, c:3, d:5, e:9] == getMergedMap(mapList, maxValue)
    assert [a:14, b:5, c:5, d:8, e:9] == getMergedMap(mapList, totalValue)
    assert [a:4, b:3, c:2, d:3, e:9] == getMergedMap(mapList, defaultValue) 
    

提交回复
热议问题