groovy:安全地在地图中找到一个键并返回它的值

Posted

技术标签:

【中文标题】groovy:安全地在地图中找到一个键并返回它的值【英文标题】:groovy: safely find a key in a map and return its value 【发布时间】:2012-12-21 05:05:23 【问题描述】:

我想在给定的地图中找到一个特定的键。如果找到键,我想从地图中获取该键的值。

这是我目前所管理的:

def mymap = [name:"Gromit", likes:"cheese", id:1234]

def x = mymap.find it.key == "likes" 

if(x)
    println x.value

这行得通,输出如预期的那样是“奶酪”。很好,但我不想在最后做x.value,我也不想做if(x)。我希望 x 以某种方式直接包含该值。

我无法像这样将值直接放入 x 中:

def mymap = [name:"Gromit", likes:"cheese", id:1234]

def x = mymap.find it.key == "likesZZZ" .value

println x

因为在这种情况下 find 闭包为空,这会导致空指针异常。当然,上面的代码sn -p在it.key == "likes"时有效,但我不确定我是否总能在map中找到目标键。

什么是在地图上执行此操作的“Groovier”和安全方式:

检查地图是否有给定的键, 如果是,则获取此键的值

【问题讨论】:

【参考方案1】:

您忘记提及当密钥不存在时会发生什么。我假设null 没问题。


可以使用property notation 查询 Groovy 地图。所以你可以这样做:

def x = mymap.likes

在这种情况下,x 将包含 mymap['likes'] 的值(如果存在),否则为 null。

如果您要查找的键(例如'likes.key')本身包含一个点,那么您可以像这样引用该键:

def x = mymap.'likes.key'

如果密钥存储在变量中,请使用带有 属性表示法的string interpolation,如下所示:

def key = 'likes'
def x = mymap."$key"

如果你不喜欢null,那么使用你使用elvis operator来分配一个默认值来代替(类似于java.util.Map.getOrDefault):

def x = mymap.someKey ?: 'default value'

现在你知道所有的秘密了。

请记住,groovy 映射仍然只是带有“enhancements”的 Java 映射,因此适用于 Java 的规则仍然适用于 groovy。值得注意的是,java.util.Map 界面中有一条注释,上面写着:

一些地图实现对它们可能包含的键和值有限制。例如,一些实现禁止空键和值,而一些实现对其键的类型有限制。尝试插入不合格的键或值会引发未经检查的异常,通常是NullPointerExceptionClassCastException。尝试查询是否存在不合格的键或值可能会引发异常,或者它可能只是返回 false;一些实现会表现出前一种行为,而另一些会表现出后者。更一般地,尝试对不合格的键或值进行操作,其完成不会导致将不合格的元素插入到映射中,这可能会引发异常,也可能会成功,这取决于实现的选择。此类异常在此接口的规范中被标记为“可选”。

基本上这就是说:并非所有地图都是相同的,因此在尝试对它们进行这些操作时,请确保您对(内部)正在处理的地图类型有所了解。这对于简单的东西应该不是问题,因为 Groovy 默认使用 java.util.LinkedHashMap

【讨论】:

【参考方案2】:

一般来说,这取决于您的地图所包含的内容。如果它有空值,事情就会变得棘手,应该使用containsKey(key)get(key, default) 来检测元素是否真的存在。在很多情况下,代码可以变得更简单,您可以定义一个默认值:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x1 = mymap.get('likes', '[nothing specified]')
println "x value: $x" 

还要注意containsKey()get() 比设置闭包检查元素mymap.find it.key == "likes" 要快得多。只有当你真的在那里做了更复杂的事情时,使用闭包才有意义。你可以例如这样做:

mymap.find // "it" is the default parameter
  if (it.key != "likes") return false
  println "x value: $it.value" 
  return true // stop searching

或者带有显式参数:

mymap.find key,value ->
  (key != "likes")  return false
  println "x value: $value" 
  return true // stop searching

【讨论】:

【参考方案3】:
def mymap = [name:"Gromit", id:1234]
def x = mymap.find it.key == "likes" ?.value
if(x)
    println "x value: $x"

println x.getClass().name

?. 检查 null 并且不会在 Groovy 中创建异常。如果键不存在,结果将是org.codehaus.groovy.runtime.NullObject

【讨论】:

太棒了。这比我选择的原始答案更时髦,更符合我的要求。标记这是答案。谢谢。 使用闭包非常昂贵。最好在那里使用def x = mymap.get("likes")?.value,效率更高 接近我的情况所需,我使用了findAll it.key in list 【参考方案4】:

您得到空指针异常的原因是因为在您的第二个示例中没有键 likesZZZ。试试:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x = mymap.find it.key == "likes" .value
if(x)
    println "x value: $x"

【讨论】:

如问题所述,我不能确定钥匙是否始终在地图中,所以我想要一种安全工作的方法(无例外),即使钥匙在或不在地图。【参考方案5】:

使用地图的重点在于直接访问。如果您确定地图中的值永远不会是 Groovy-false,那么您可以这样做:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def key = "likes"

if(mymap[key]) 
    println mymap[key]

但是,如果该值可能是 Groovy-false,您应该使用:

if(mymap.containsKey(key)) 
    println mymap[key]

不过,如果您知道该值不会是 Groovy-false(或者您可以忽略它)并且想要一个默认值,那么最简单的解决方案是这样的:

def value = mymap[key] ?: "default"

所有这三个解决方案都比您的示例快得多,因为它们不会扫描整个地图以查找键。他们利用了HashMap(或LinkedHashMap)设计,使直接密钥访问几乎瞬间完成。

【讨论】:

如果需要默认值,可以将映射定义为def map = [:].withDefault "Default"。那么你就不需要使用 Elvis Operator 作为默认值了。当然,这也会更新地图,所以如果你不想这样,那么猫王就是你的方式。 Key 也可以用双引号引起来,例如 def headers = ["Content-Type":"application/json"]

以上是关于groovy:安全地在地图中找到一个键并返回它的值的主要内容,如果未能解决你的问题,请参考以下文章

PHP怎么搜索数组的键并查找到对应的值?

在 groovy 地图中获取密钥

如何借用 RefCell<HashMap>、找到键并返回对结果的引用? [复制]

在反应中映射对象键并返回子属性

无法在groovy中拆分jsonobject中的值

在 Groovy 中循环遍历地图?