groovy 嵌套地图更新值而不检查值的类型

groovy nested map update value without checking type of value

我有两张地图,

def configmap = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s","env.required.test":"new", "env.optional.anotherkey":"newvalue" ]

valuesReplacementMap 具有指向 configmap 中的键的路径以及需要更新的新值。

我需要将 configmap 中的值更新为 valuesReplacementMap

中给定的值

这是我的代码,有效


def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
           "env.required.test":"new",
           "env.optional.anotherkey":"newvalue" ]

def copyofOrigMap
valuesReplacementMap.each{ key, value->
    copyofOrigMap = m
    key.tokenize(".").inject{ attr, val ->
        if(copyofOrigMap[attr][val] instanceof java.lang.String ){
            copyofOrigMap[attr][val] = value
        }else 
            copyofOrigMap = copyofOrigMap[attr]
        val
    }
}

我的问题是

  1. 有没有一种方法可以避免检查 instanceof java.lang.String,我这样做是为了查看是否到达叶 node/key
  2. 有没有更简单的方法来实现这整个功能

我查看了一些较早发布的问题,但没有找到任何优化方法

  1. Updating value in a map while iterating the map groovy

解决此问题的一种方法是 Eval.me。以下代码:

def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
                           "env.required.test":"new",
                           "env.optional.anotherkey":"newvalue" ]

valuesReplacementMap.each { k, v -> 
  Eval.me('m', m, "m.${k} = '${v}'")
}

m.each { k, v -> 
  println "$k -> $v"
}

执行结果为:

─➤ groovy solution.groovy                                          
env -> [required:[team:s, test:new], optional:[anotherkey:newvalue]]
─➤ 

(在 Groovy 版本:3.0.5 JVM:11.0.8 供应商:Amazon.com Inc. OS:Linux)

Eval.me 方法的第一个参数 'm' param 告诉 eval 我们希望字符串表达式中的值绑定到名称 m,第二个参数是值本身。第三个参数是要计算的表达式。

可能有比 eval 更优雅的东西,但它非常简洁,可以为您提供所需的结果。

还应注意,这仅适用于字符串值,如果任何键或值来自用户输入,从安全角度来看使用 Eval 可能是危险的。

编辑可能具有更好的安全隐患

作为替代方案,您可以这样做:

def m = [ "env" :["required": ["team" : "k", "test": "sample"], "optional" : ["anotherkey" : ""]]]
def valuesReplacementMap=[ "env.required.team":"s",
                           "env.required.test":"new",
                           "env.optional.anotherkey":"newvalue" ]


valuesReplacementMap.each { k, v -> 
  def tokens = k.tokenize('.')
  def last = tokens.init().inject(m) { a, t -> a[t] }
  last[tokens.last()] = v
}

m.each { k, v -> 
  println "$k -> $v"
}

产生的输出与上面的 Eval.me 示例相同。