【问题标题】:Can ruby deep search a hash/array for a particular key?ruby 可以深度搜索哈希/数组中的特定键吗?
【发布时间】:2014-07-01 10:04:13
【问题描述】:

我有一些 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")

【问题讨论】:

    标签: ruby arrays json api hash


    【解决方案1】:

    使用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
    

    【讨论】:

    • ...如果不存在?
    • 它会返回 nil 对吗?我已经没有在我的代码中检查这个值以用于其他目的。
    • @Kronusdark,如果没有匹配的项目,它将抛出异常NoMethodError,因为Enumerable#find 返回nil
    • h.has_key?('lastBuiltRevision') 应该够了,为什么fetch
    • @VictorMoroz,你是对的。我根据你更新了答案。感谢您的评论。
    【解决方案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
    

    【讨论】:

      【解决方案3】:

      试试:

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

      【讨论】:

      • 比我想要的有点冗长,但它有效并且不那么循环(至少在外观上)
      • @Kronusdark 仅在您需要时扫描和处理所有操作,find 是更好的方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多