Reputation: 1388
If I have a Hash
such as with subhashes, which are nested in arrays of the value of a Hash
:
{"school" => "School name", "teachers" => [{"name" => "Schmith", "age" => 34},{"name" => "McRight", "age" => 51}]}
def get_keys(hash)
(hash.keys + hash.values.grep(Hash){|sub_hash| get_keys(sub_hash)}).flatten
end
With the previous function I can get only ["school","teachers"]
, but I need also the keys of the hashes, which are in the array of the "teachers" value: ["school","teachers","name","age","name","age"]
Preferable I would like to eliminate duplications in the result to have: ["school","teachers","name","age"]
Upvotes: 0
Views: 1743
Reputation: 15987
You can use Enumerable#each_with_object
to do something like this and when the value is an Array, call the same function recursively for each object in the array.
hash = {"school" => "School name", "teachers" => [{"name" => "Schmith", "age" => 34},{"name" => "McRight", "age" => 51}]}
def get_keys(hash)
hash.each_with_object([]) do |(k, v), arr|
arr << k
if v.is_a? Array
arr << v.map { |hash2| get_keys(hash2) }.uniq
end
end
end
puts get_keys(hash)
=> ["school", "teachers", "name", "age"]
Upvotes: 2
Reputation: 1267
def get_keys(object)
if object.is_a? Hash
(object.keys + get_keys(object.values)).flatten.uniq
elsif object.is_a? Array
object.collect{|value| get_keys value}
else
[]
end
end
I think this is quite clear, and you can nest as much as you want.
If the object is not an array or hash, then there are no keys.
If it's an array, it will look for the keys that could be in all the elements
And if it's a hash, it will return its keys, plus the keys of the hashes that could be on the values of the hash. Then you apply flatten
to remove possible empty arrays, and uniq
to remove duplicate values.
With arrays, it will get the keys that could be inside of the
Upvotes: 2