Léo
Léo

Reputation: 810

How collect values of a specified key recursively in a Array/Hash

I have the following Array (no limit of deepness) :

 [
   {
     name: "foo",
     age: 12,
     children: [{
         name: "zoo",
         age: 44
       },
       {
         name: "taz",
         age: 17,
         children: [{
             name: 'tof',
             age: 23
           },
           {
             name: 'tok',
             age: 42
           }
         ]
       }
     ]
   },
   {
     name: "bar",
     age: 54
   }
 ]

And I would like to collect all the different values of the key name, in this example the result would be:

(the order does not matter)

['foo', 'zoo', 'taz', 'tof', 'tok', 'bar']

with a function like

def func(my_array, "name")

Do you have any idea how I should code that function ?

Upvotes: 1

Views: 199

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110675

def find_em(arr)
  arr.each_with_object([]) do |h,a|
    a << h[:name]
    a.concat(find_em(h[:children])) if h.key?(:children)
  end
end

find_em(arr)
  #=> ["foo", "zoo", "taz", "tof", "tok", "bar"] 

Upvotes: 0

mccalljt
mccalljt

Reputation: 796

Heres a fast but brittle regex way of doing it

def find_nested(arr, key)
  arr.to_s.scan(/#{key.to_sym}=>"([^"]+)/).flatten
end

Upvotes: 2

ndnenkov
ndnenkov

Reputation: 36101

Assuming you know the substructure is under :children:

def extract(sequence, key)
  sequence.flat_map do |hash|
    [hash[key], *extract(hash[:children] || [], key)]
  end
end

Upvotes: 4

tadman
tadman

Reputation: 211560

Here's a way of doing it using case to differentiate between the various object types you'll encounter:

def find_names(object, key_name)
  case (object)
  when Array
    object.flat_map do |e|
      find_names(e, key_name)
    end
  when Hash
    [ object[key_name] ] + find_names(object.values, key_name).compact
  end
end

Upvotes: 2

Related Questions