Ruby能否深入搜索哈希/数组以查找特定的键?

3
我有一些Ruby代码,它从Jenkins获取一个包含n个元素的JSON数组。我想要的项目有一个名为“lastBuiltRevision”的键。
我知道可以像这样循环遍历数组:
actions.each do |action| 
    if action["lastBuiltRevision"]
        lastSuccessfulRev = action["lastBuiltRevision"]["SHA1"]
        break
    end
end

但这种方法感觉非常笨拙,缺乏我通常在使用Ruby时所感受到的魔力。

我只是尝试了大约一周左右,感觉可能还缺少某些东西使它变得更容易、更快速。

有这样的东西吗?或者手动迭代就是我唯一能做的事情吗?

我有点希望能有类似于

lastSuccessfulRev = action.match("lastBuildRevision/SHA1")
3个回答

4

使用Enumerable#find方法:

actions = [
  {'dummy' => true },
  {'dummy' => true },
  {'dummy' => true },
  {'lastBuiltRevision' => { "SHA1" => "123abc" }},
  {'dummy' => true },
]
actions.find { |h|
  h.has_key? 'lastBuiltRevision'
}['lastBuiltRevision']['SHA1']
# => "123abc"

更新

如果没有匹配项,则上述代码将抛出NoMethodError异常。如果不想得到异常,请使用以下代码。

rev = actions.find { |h| h.has_key? 'lastBuiltRevision' }
rev = rev['lastBuiltRevision']['SHA1'] if rev

1
...如果不存在呢? - Uri Agassi
它会返回 nil,对吧?我已经在我的代码中检查了这个值以进行其他用途。 - Weston
2
@Kronusdark,它会抛出异常NoMethodError,因为如果没有匹配项,Enumerable#find会返回nil - falsetru
h.has_key?('lastBuiltRevision') 应该足够了,为什么要用 fetch - Victor Moroz
@VictorMoroz,你是对的。我根据你的意见更新了答案。感谢你的评论。 - falsetru
ft,为什么在第一个键不存在时选择引发异常,但仅在第二个键不存在时返回nil?您可以考虑使用h = actions.find { |h| h.has_key? 'lastBuiltRevision'}; h ? h['lastBuiltRevision']['SHA1'] : nil - Cary Swoveland

2
这里有另一种方法来做到这一点,利用Enumerable#find的形式,该方法接受一个参数ifnone,如果find的块从未评估为true,则调用该参数并返回其返回值。
我假设该方法在找不到键时返回nil代码
def look_for(actions, k1, k2)
  actions.find(->{{k1=>{}}}) { |e| e.key?(k1) }[k1][k2]
end

例子

actions = [{ 'dog'=>'woof' }, { 'lastBuiltRevision'=>{ 'SHA1'=> 2 } }]

look_for(actions, 'lastBuiltRevision', 'SHA1') #=> 2
look_for(actions, 'cat, 'SHA1')                #=> nil
look_for(actions, 'lastBuiltRevision', 'cat')  #=> nil

解释

我把findifnone参数设置为lambda函数:

l = ->{{k1=>{}}}

所以:

k1 = "cats"
h  = l.call   #=> {"cats"=>{}}
h[k1]['SHA1'] #=> {}['SHA1']
              #=> nil

1

尝试:

action.map { |a| a["lastBuiltRevision"] }.compact.map { |lb| lb["SHA1"] }.first

比我想象中要啰嗦一些,但它能够工作并且看起来不那么循环(至少表面上是这样)。 - Weston
2
@Kronusdark 只有在你需要一个扫描和处理所有操作的时候,find 才是更好的选择。 - Victor Moroz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接