1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
class Hash def fetch_all(key) results = [] hashfinder = lambda {|h| arrayfinder = lambda {|a| a.each do |v| hashfinder[v] if v.is_a?(Hash) arrayfinder[v] if v.is_a?(Array) end } if h.has_key?(key) results << h.fetch(key) end h.values.each do |v| hashfinder[v] if v.is_a?(Hash) arrayfinder[v] if v.is_a?(Array) end } hashfinder.call(self) results end end
Refactorings
No refactoring yet !
jes5199
March 21, 2008, March 21, 2008 00:20, permalink
well, since we're already reopening standard classes, I thought it might make sense to move the Array logic into class Array. Now we have simple recursion of methods, instead of having to make private functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Hash def fetch_all(key) return [] if not self.has_key?(key) value = self.fetch(key) [ value ] + [ value ].fetch_all(key) end end class Array def fetch_all(key) self.find_all{|x| x.respond_to? :fetch_all} \ .map{|x| x.fetch_all(key) } \ .inject( [] ){|a,b| a + b } end end
I wanted a Hash#fetch that would return all matches for a particular key in a hash with nested hashes and arrays, and this is what I came up with. I'm pretty new to Ruby, so I can't help but think there's a better way to do it.