我有一个非常嵌套的Json响应。Ruby从json响应中搜索超级嵌套密钥
[[{:test=>[{:id=>1, :b=>{id: '2'}}]}]]
还有更多的数组,但你明白了。 有没有办法通过递归搜索并找到所有有我需要的密钥的项目?
我试过使用这个函数extract_list(),但它不能很好地处理数组。
我有一个非常嵌套的Json响应。Ruby从json响应中搜索超级嵌套密钥
[[{:test=>[{:id=>1, :b=>{id: '2'}}]}]]
还有更多的数组,但你明白了。 有没有办法通过递归搜索并找到所有有我需要的密钥的项目?
我试过使用这个函数extract_list(),但它不能很好地处理数组。
您需要编写自己的递归处理函数。假设你已经转换了您的JSON到一个Ruby数据结构(通过JSON.load或诸如此类的东西):
def deep_find_value_with_key(data, desired_key)
case data
when Array
data.each do |value|
if found = deep_find_value_with_key value, desired_key
return found
end
end
when Hash
if data.key?(desired_key)
data[desired_key]
else
data.each do |key, val|
if found = deep_find_value_with_key(val, desired_key)
return found
end
end
end
end
return nil
end
总的想法是,给定的数据结构,你选择了它的键(如果它是一个散列),并返回匹配的值,如果找到。否则,你迭代它(如果它是一个Array或Hash)并对它的每个子进行相同的检查。
这将查找给定键的第一个匹配项的值,如果该键不存在于树中,则为零。如果你需要找到所有情况下,那么它的略有不同 - 你基本上需要传递一个阵列,将累积值:
def deep_find_value_with_key(data, desired_key, hits = [])
case data
when Array
data.each do |value|
deep_find_value_with_key value, desired_key, hits
end
when Hash
if data.key?(desired_key)
hits << data[desired_key]
else
data.each do |key, val|
deep_find_value_with_key(val, desired_key)
end
end
end
return hits
end
嗯所有的实例(或两者)似乎并没有工作我试着'放deep_find_value_with_key(data,:api).inspect' –
我没有测试代码 - 它可能需要一些调整。但总体思路是正确的 - 您必须对数据进行深度迭代,每次遇到散列时都要检查密钥。你可能需要做一些动作来确保它适合你的情况。 –
def nested_find(obj, needed_keys)
return {} unless obj.is_a?(Array) || obj.is_a?(Hash)
obj.inject({}) do |hash, val|
if val.is_a?(Hash) && (tmp = needed_keys & val.keys).length > 0
tmp.each { |key| hash[key] = val[key] }
elsif val.is_a?(Array)
hash.merge!(obj.map { |v| nested_find(v, needed_keys) }.reduce(:merge))
end
hash
end
end
needed_keys = [:id, :another_key]
nested_find([ ['test', [{id:1}], [[another_key: 5]]]], needed_keys)
# {:id=>1, :another_key=>5}
下面是不是有什么我建议,但只是为了给出一个简短的替代方案提供的其他解决方案:
2.1.1 :001 > obj = [[{:test=>[{:id=>1, :b=>{id: '2'}}]}]]
=> [[{:test=>[{:id=>1, :b=>{:id=>"2"}}]}]]
2.1.1 :002 > key = :id
=> :id
2.1.1 :003 > obj.inspect.scan(/#{key.inspect}=>([^,}]*)[,}]/).flatten.map {|s| eval s}
=> [1, "2"]
注意:这里使用eval仅仅是一个例子。对于任何其检查值无法评估的事件,它会失败/产生不正确的结果,并且可能执行恶意代码:
JSON响应格式错误。不匹配的括号? ('[{id:1]}')没有值的密钥? ('{test,')括号和大括号的数量不是很多? – Ajedi32
编辑示例使其不那么畸形并且具有相同的密钥两次,因为提到“查找所有具有我需要的密钥的项目”。 –