b-m-f
b-m-f

Reputation: 1328

Find multiple objects in nested hash

I'm am getting a nested hash from Facebook. It has arrays inside which have more hashes and vice versa.

Now I am trying to find every occurence of a hash that is deeply nested.

In my case I am searching for every value that has the key "tags" and then push it into an array.

I have found a solution for a unique key in "Find key/value pairs deep inside a hash containing an arbitrary number of nested hashes and arrays".

How can I do the same thing when the key is not unique and push every result into an array?

Edit:

Here is an example response I am getting from the facebook graph api.

{"albums"=>{"data"=>[{"id"=>"1406826642942218", 
"created_time"=>"2014-12-11T10:54:13+0000", 
"photos"=>{"data"=>[{"created_time"=>"2014-12-11T10:54:13+0000",
 "id"=>"1406826626275553"}], 
"paging"=>{"cursors"=>{"before"=>"MTQwNjgyNjYyNjI3NTU1Mw==", "after"=>"MTQwNjgyNjYyNjI3NTU1Mw=="}}}},
 {"id"=>"1406825849608964", 
"created_time"=>"2014-12-11T10:52:34+0000", 
"photos"=>{"data"=>[{"created_time"=>"2014-12-11T10:52:34+0000", 
"id"=>"1406825782942304"}], 
"paging"=>{"cursors"=>{"before"=>"MTQwNjgyNTc4Mjk0MjMwNA==", "after"=>"MTQwNjgyNTc4Mjk0MjMwNA=="}}}},
 {"id"=>"1405097859781763",
 "created_time"=>"2014-12-08T14:50:51+0000"
, "photos"=>{"data"=>[{"created_time"=>"2014-12-08T14:51:12+0000", "id"=>"1405097983115084"}],
 "paging"=>{"cursors"=>{"before"=>"MTQwNTA5Nzk4MzExNTA4NA==", "after"=>"MTQwNTA5Nzk4MzExNTA4NA=="}}}},
 {"id"=>"1392256877732528",
 "created_time"=>"2014-11-17T14:37:00+0000",
 "photos"=>{"data"=>[{"created_time"=>"2014-12-08T14:24:41+0000", 
"id"=>"1405084986449717"}, 
{"tags"=>{"data"=>[{"id"=>"100007516267052",
 "name"=>"Dorothy Amgeafbfgjeb Qinman",
 "created_time"=>"2014-11-17T14:37:12+0000",
 "x"=>46.604215456674, "y"=>72.330827067669}, 
{"id"=>"100007456544855", 
"name"=>"Richard Amgdefeddhee Carrierosen",
 "created_time"=>"2014-11-17T14:37:11+0000",
 "x"=>45.433255269321, "y"=>48.571428571429}, 
{"id"=>"100008446877693", 
"name"=>"Karen Amhddfhggfic Chaison",
 "created_time"=>"2014-11-17T14:37:09+0000",
 "x"=>49.414519906323, "y"=>31.578947368421}],
 "paging"=>{"cursors"=>{"before"=>"MTAwMDA3NTE2MjY3MDUy", "after"=>"MTAwMDA4NDQ2ODc3Njkz"}}},
 "created_time"=>"2014-11-17T14:37:01+0000",
 "id"=>"1392256757732540"}], 
"paging"=>{"cursors"=>{"before"=>"MTQwNTA4NDk4NjQ0OTcxNw==", "after"=>"MTM5MjI1Njc1NzczMjU0MA=="}}}}],
 "paging"=>{"cursors"=>{"after"=>"MTM5MjI1Njg3NzczMjUyOA==", "before"=>"MTQwNjgyNjY0Mjk0MjIxOA=="}}},
 "id"=>"100008446877693"}

What I want to get is this part

{"tags"=>{"data"=>[{"id"=>"100007516267052",
     "name"=>"Dorothy Amgeafbfgjeb Qinman",
     "created_time"=>"2014-11-17T14:37:12+0000",
     "x"=>46.604215456674, "y"=>72.330827067669}, 
    {"id"=>"100007456544855", 
    "name"=>"Richard Amgdefeddhee Carrierosen",
     "created_time"=>"2014-11-17T14:37:11+0000",
     "x"=>45.433255269321, "y"=>48.571428571429}, 
    {"id"=>"100008446877693", 
    "name"=>"Karen Amhddfhggfic Chaison",
     "created_time"=>"2014-11-17T14:37:09+0000",
     "x"=>49.414519906323, "y"=>31.578947368421}],

Which could be at multiple places depending on how many pictures have tags on them.

I hope this makes it more clear.

Upvotes: 0

Views: 1070

Answers (1)

dfherr
dfherr

Reputation: 1642

def nested_hash_values(obj,key)
  r = []  
  if obj.is_a?(Hash)        
    r.push(obj[key]) if obj.key?(key) 
    obj.each_value { |e| r += nested_hash_values(e,key) }
  end
  if obj.is_a?(Array)
    obj.each { |e| r += nested_hash_values(e,key) }
  end
  r
end

a = {"foo"=>["bar", "x", {"bar"=>["hello", {"foo"=>"world"}, "world!"], "foo"=>"BAR!"}, "enough?"], "bar"=>"foo"}
nested_hash_values(a, "foo")
=> [["bar", "x", {"bar"=>["hello", {"foo"=>"world"}, "world!"], "foo"=>"BAR!"}, "enough?"], "BAR!", "world"]

should return an array with all values found for a given key.

You could add additional if e.is_a?(Array) || e.is_a?(Hash) in the each blocks. This would avoid unnecessary method calls and speed the function up a little, but add additional code.

Upvotes: 1

Related Questions