我有一个非常嵌套的Json响应。
[[{:test=>[{:id=>1, :b=>{id: '2'}}]}]]
还有更多阵列,但你明白了。 有没有办法递归搜索并找到所有具有我需要的密钥的项目?
我尝试使用此函数extract_list(),但它并没有很好地处理数组。
答案 0 :(得分:1)
以下不是我的建议,只是为了提供其他解决方案的简要替代方案:
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只是一个例子。如果检查值无法回复到同一个实例,它会失败/产生不正确的结果,并且它可以执行恶意代码:
答案 1 :(得分:0)
您需要编写自己的递归处理程序。假设您已经将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
一般的想法是,给定一个数据结构,你检查它是否为密钥(如果它是一个哈希)并返回匹配值(如果找到)。否则,你迭代它(如果它是一个数组或哈希)并对它的每个孩子执行相同的检查。
这将找到给定键第一次出现的值,如果树中不存在该键则为nil。如果您需要找到所有实例,那么它稍有不同 - 您基本上需要传递一个将累积值的数组:
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
答案 2 :(得分:0)
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}