Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find key/value pairs deep inside a hash containing an arbitrary number of nested hashes and arrays

A web service is returning a hash that contains an unknown number of nested hashes, some of which contain an array, which in turn contains an unknown number of nested hashes.

Some of the keys are not unique -- i.e. are present in more than one of the nested hashes.

However, all the keys that I actually care about are all unique.

Is there someway I can give a key to the top-level hash, and get back it's value even if the key-value pair is buried deep in this morass?

(The web service is Amazon Product Advertising API, which slightly varies the structure of the results that it gives depending on the number of results and the search types permitted in each product category.)

like image 741
steven_noble Avatar asked Nov 28 '11 19:11

steven_noble


2 Answers

Here's a simple recursive solution:

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 
like image 179
Phrogz Avatar answered Oct 02 '22 04:10

Phrogz


No need for monkey patching, just use 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' } 

For arbitrary Enumerable objects, there is another extension available, DeepLocate: https://github.com/intridea/hashie#deeplocate

like image 34
denis.peplin Avatar answered Oct 02 '22 06:10

denis.peplin