Ruby: Get all keys in a hash (including sub keys)
I find grep
useful here:
def get_keys(hash)
( hash.keys + hash.values.grep(Hash){|sub_hash| get_keys(sub_hash) } ).flatten
end
p get_keys my_nested_hash #=> ["a", "b", "c"]
I like the solution as it is short, yet it reads very nicely.
This will give you an array of all the keys for any level of nesting.
def get_em(h)
h.each_with_object([]) do |(k,v),keys|
keys << k
keys.concat(get_em(v)) if v.is_a? Hash
end
end
hash = {"a" => 1, "b" => {"c" => {"d" => 3}}}
get_em(hash) # => ["a", "b", "c", "d"]
Version that keeps the hierarchy of the keys
- Works with arrays
- Works with nested hashes
keys_only.rb
# one-liner
def keys_only(h); h.map { |k, v| v = v.first if v.is_a?(Array); v.is_a?(Hash) ? [k, keys_only(v)] : k }; end
# nicer
def keys_only(h)
h.map do |k, v|
v = v.first if v.is_a?(Array);
if v.is_a?(Hash)
[k, keys_only(v)]
else
k
end
end
end
hash = { a: 1, b: { c: { d: 3 } }, e: [{ f: 3 }, { f: 5 }] }
keys_only(hash)
# => [:a, [:b, [[:c, [:d]]]], [:e, [:f]]]
P.S.: Yes, it looks like a lexer :D
Bonus: Print the keys in a nice nested list
# one-liner
def print_keys(a, n = 0); a.each { |el| el.is_a?(Array) ? el[1] && el[1].class == Array ? print_keys(el, n) : print_keys(el, n + 1) : (puts " " * n + "- #{el}") }; nil; end
# nicer
def print_keys(a, n = 0)
a.each do |el|
if el.is_a?(Array)
if el[1] && el[1].class == Array
print_keys(el, n)
else
print_keys(el, n + 1)
end
else
puts " " * n + "- #{el}"
end
end
nil
end
> print_keys(keys_only(hash))
- a
- b
- c
- d
- e
- f