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
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, 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
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
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条答案
按热度按时间6tr1vspr1#
下面是一个简单的递归解决方案:
3qpi33ja2#
不需要猴子补丁,只需使用Hashie gem:https://github.com/intridea/hashie#deepfind
对于任意的可枚举对象,还有另一个可用的扩展DeepLocate:https://github.com/intridea/hashie#deeplocate
h22fl7wq3#
结合以上几个答案和评论:
fhg3lkii4#
Ruby 2.3引入了Hash#dig,它允许您执行以下操作:
2lpgd9685#
一个几乎不为人知的解的变体:这将在散列中查找键的所有值,而不是第一个匹配项。
{a: [{b: 1}, {b: 2}]}.deep_find(:b)
将返回uqjltbpv6#
尽管这似乎是一个常见的问题,我只是花了一段时间试图找到/拿出我到底需要什么,我认为这是相同的要求。没有一个链接在第一次回应是正确的。
因此:
以下内容:
将查找与:transaction键关联的数组。
这不是最佳的,因为即使填充了 memo,注入也会继续迭代。
yrefmtwq7#
我使用以下代码
gblwokeq8#
最后我用它做了一个小的trie搜索,我写道:
注意:这只是针对嵌套的散列,目前不支持数组。
72qzrwbm9#
因为Rails 5 ActionController::Parameters不再从Hash继承,所以我必须修改该方法,使其特定于参数。
如果找到键,则返回该键的值,但不返回ActionController::Parameter对象,因此不保留强参数。