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
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
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
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
{a: [{b: 1}, {b: 2}]}.deep_find(:b) 将返回 [1, 2]
9
我使用以下代码
def search_hash(hash, key)
return hash[key] if hash.assoc(key)
hash.delete_if{|key, value| value.class != Hash}
new_hash = Hash.new
hash.each_value {|values| new_hash.merge!(values)}
unless new_hash.empty?
search_hash(new_hash, key)
end
end
29
我最后用这个用于我写的一个小小的搜索:
def trie_search(str, obj=self)
if str.length <= 1
obj[str]
else
str_array = str.chars
next_trie = obj[str_array.shift]
next_trie ? trie_search(str_array.join, next_trie) : nil
end
end
module ActionController
class Parameters
def deep_find(key, object=self, found=nil)
if object.respond_to?(:key?) && object.key?(key)
return object[key]
elsif object.respond_to?(:each)
object = object.to_unsafe_h if object.is_a?(ActionController::Parameters)
object.find { |*a| found = deep_find(key, a.last) }
return found
end
end
end
end
9 回答
这是一个简单的递归解决方案:
结合上面的一些答案和评论:
不需要猴子修补,只需使用Hashie gem:https://github.com/intridea/hashie#deepfind
对于任意Enumerable对象,还有另一个可用的扩展名DeepLocate:https://github.com/intridea/hashie#deeplocate
尽管这似乎是一个常见的问题,但我花了一些时间试图找到/提出我需要的东西,我认为这与你的要求是一样的 . 第一个响应中的任何一个链接都没有点击 .
所以给出:
下列:
将找到与:transaction键关联的数组 .
这不是最佳的,因为即使填充了备忘录,注入也将继续迭代 .
勉强知道解决方案的变体:这将在哈希中找到密钥的所有值,而不是第一个匹配 .
{a: [{b: 1}, {b: 2}]}.deep_find(:b)
将返回[1, 2]
我使用以下代码
我最后用这个用于我写的一个小小的搜索:
注意:这仅适用于嵌套哈希 . 目前没有阵列支持 .
因为Rails 5 ActionController :: Parameters不再继承Hash,所以我必须修改方法并使其特定于参数 .
如果找到该键,则返回该键的值,但它不返回ActionController :: Parameter对象,因此不保留Strong Parameters .
Ruby 2.3引入了Hash#dig,它允许你这样做: