Phr*_*ogz 32
这是一个简单的递归解决方案:
def nested_hash_value(obj,key)
if obj.respond_to?(:key?) && obj.key?(key)
obj[key]
elsif obj.respond_to?(:each)
r = nil
obj.find{ |*a| r=nested_hash_value(a.last,key) }
r
end
end
h = { foo:[1,2,[3,4],{a:{bar:42}}] }
p nested_hash_value(h,:bar)
#=> 42
Run Code Online (Sandbox Code Playgroud)
den*_*lin 25
不需要猴子修补,只需使用Hashie gem:https://github.com/intridea/hashie#deepfind
user = {
name: { first: 'Bob', last: 'Boberts' },
groups: [
{ name: 'Rubyists' },
{ name: 'Open source enthusiasts' }
]
}
user.extend Hashie::Extensions::DeepFind
user.deep_find(:name) #=> { first: 'Bob', last: 'Boberts' }
Run Code Online (Sandbox Code Playgroud)
对于任意Enumerable对象,还有另一个可用的扩展,DeepLocate:https://github.com/intridea/hashie#deeplocate
bar*_*own 24
结合上面的一些答案和评论:
class Hash
def deep_find(key, object=self, found=nil)
if object.respond_to?(:key?) && object.key?(key)
return object[key]
elsif object.is_a? Enumerable
object.find { |*a| found = deep_find(key, a.last) }
return found
end
end
end
Run Code Online (Sandbox Code Playgroud)
尽管这似乎是一个常见的问题,但我花了一些时间试图找到/提出我需要的东西,我认为这与你的要求相同.第一个响应中的任何一个链接都没有点击.
class Hash
def deep_find(key)
key?(key) ? self[key] : self.values.inject(nil) {|memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
end
end
Run Code Online (Sandbox Code Playgroud)
所以给出:
hash = {:get_transaction_list_response => { :get_transaction_list_return => { :transaction => [ { ...
Run Code Online (Sandbox Code Playgroud)
下列:
hash.deep_find(:transaction)
Run Code Online (Sandbox Code Playgroud)
将找到与:transaction键关联的数组.
这不是最佳的,因为即使填充了备忘录,注入也将继续迭代.
勉强知道解决方案的变体:这将在哈希中找到密钥的所有值,而不是第一个匹配.
class Hash
def deep_find(key, object=self, found=[])
if object.respond_to?(:key?) && object.key?(key)
found << object[key]
end
if object.is_a? Enumerable
found << object.collect { |*a| deep_find(key, a.last) }
end
found.flatten.compact
end
end
Run Code Online (Sandbox Code Playgroud)
{a: [{b: 1}, {b: 2}]}.deep_find(:b) 将返回 [1, 2]
Ruby 2.3引入了Hash#dig,它允许您执行以下操作:
h = { foo: {bar: {baz: 1}}}
h.dig(:foo, :bar, :baz) #=> 1
h.dig(:foo, :zot) #=> nil
Run Code Online (Sandbox Code Playgroud)