我遇到了遍历哈希的这个函数的问题。哈希可能包含一个哈希数组。我希望该方法搜索一个id,然后只返回它找到的嵌套哈希。
它似乎适用于遍历,但它返回传入的原始值。
require 'rubygems'
require 'ruby-debug'
def find_by_id(node, find_this="")
if node.is_a?(Hash)
node.each do |k,v|
if v.is_a?(Array)
v.each do |elm|
if elm["_id"] == find_this && !find_this.empty?
return elm # THIS IS WHAT I WANT!
else
find_by_id(elm, find_this)
end
end
end
end
end
end
x = {"name" => "first", "_id"=>'4c96a9a56f831b0eb9000005', "items"=>["name" => "second", "_id"=>'4c96a9af6f831b0eb9000009', "others"=>[{"name" => "third", "_id"=>'4c96a9af6f831b0eb9000007'}, {"name" => "fourth", "_id"=>'4c96a9af6f831b0eb9000008'}] ] }
find_by_id(x, '4c96a9af6f831b0eb9000008')
答案 0 :(得分:11)
当您递归调用find_by_id
时,您没有对返回值执行任何操作。您需要检查它是否找到了某些东西,如果是这样的话,那就是:
result = find_by_id(elm, find_this)
return result if result
您还需要在方法结束时(在每个循环之后)返回nil
,因此如果未找到任何内容,则返回nil
。如果不这样做,它将返回each
的返回值,这是您迭代的哈希值。
编辑:
以下是我概述的更改的完整代码:
def find_by_id(node, find_this="")
if node.is_a?(Hash)
node.each do |k,v|
if v.is_a?(Array)
v.each do |elm|
if elm["_id"] == find_this && !find_this.empty?
return elm # THIS IS WHAT I WANT!
else
result = find_by_id(elm, find_this)
return result if result
end
end
end
end
end
# Return nil if no match was found
nil
end
EDIT2:
我觉得更清晰的另一种方法是将用于迭代结构的逻辑与用于查找具有正确id的元素的逻辑分开:
def dfs(hsh, &blk)
return enum_for(:dfs, hsh) unless blk
yield hsh
hsh.each do |k,v|
if v.is_a? Array
v.each do |elm|
dfs(elm, &blk)
end
end
end
end
def find_by_id(hsh, search_for)
dfs(hsh).find {|node| node["_id"] == search_for }
end
通过dfs
返回Enumerable
,我们可以使用Enumerable#find
方法,这会使代码更简单。
如果您需要编写另一个需要以递归方式遍历哈希的方法,这也可以重用代码,因为您可以重用dfs方法。