Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate through all values of a nested map in groovy

Tags:

groovy

I have a nested map of unknown structure, the goal is to iterate through every value in the map, check the values of a certain condition (e.g. null) and replace those values with something else. I can see how to do it if the map structure is known, but the issue here is that it is unknown.

For example this could be the map structure passed (or could have any number of nested maps):

​def map = [
          a:5,
          b:"r",
          c:[ a1:0, b1:null ],
          d:[ a2: [ a3:"", b3:99 ], b2:null ],
          ...
]

Normally for a simple map one would use a this to update values:

map.each { it.value == null ? it.value = "" : "" }

However with an nested map structure this approach will not work.

Is there an efficient way to iterating through all the nested values of an unknown map to investigate and update the values?

like image 798
rboy Avatar asked Dec 18 '22 21:12

rboy


2 Answers

You can run that with each, but you need to recurse for maps then. E.g. see deNull.

def deNull(def root) {
    root.each{
        if (it.value instanceof Map) {
            deNull(it.value)
        } else if (it.value==null) {
            it.value = ""
        }
    }
}

def map = [
    a:5,
    b:"r",
    c:[ a1:0, b1:null ],
    d:[ a2: [ a3:"", b3:99 ], b2:null ],
]
println(map.tap{ deNull it }.inspect())
// => ['a':5, 'b':'r', 'c':['a1':0, 'b1':''], 'd':['a2':['a3':'', 'b3':99], 'b2':'']]

For a proper approach i'd also pass in a closure for "what to do" instead of just dealing with the "de-null-ing" here (which makes that reuseable) and name it postwalkMap or something like that.

like image 172
cfrick Avatar answered Mar 07 '23 15:03

cfrick


You can also use Map.replaceAll(BiFunction<String, Serializable, Serializable>) func) to replace all nulls recursively in a map of an unknown structure.

Consider following example:

import java.util.function.BiFunction

def map = [
        a: 5,
        b: "r",
        c: [a1: 0, b1: null],
        d: [a2: [a3: "", b3: 99], b2: null]
]

def nullsWith(Object replacement) {
    return { String key, Serializable value ->
        if (value instanceof Map) {
            value.replaceAll(nullsWith(replacement))
            return value
        }
        return value == null ? replacement : value
    } as BiFunction<String, Serializable, Serializable>
}

map.replaceAll nullsWith("null replacement")

println map.inspect()

Output:

['a':5, 'b':'r', 'c':['a1':0, 'b1':'null replacement'], 'd':['a2':['a3':'', 'b3':99], 'b2':'null replacement']]
like image 39
Szymon Stepniak Avatar answered Mar 07 '23 15:03

Szymon Stepniak