HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Deeply extract all used symbols from a hash of nested symbols in an array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
allarrayuseddeeplyhashnestedextractfromsymbols

Problem

I have a nested hash of symbols like this:

{
  a: {
    b: :c,
    d: {
      e: :f
    }
  },
  g: :h
}


I want to build an array that contains all symbols used in the hash, both keys and values, in any order. For the example above:

[:a, :b, :c, :d, :e, :f, :g, :h]


Is there any simple, fast and ruby-friendly way to do this?

I'm doing this with a recursive function that sums hash.keys with hash.values, and finally applies flatten to the result.

def all_keys(hash)
  hash.keys + hash.values.map { |e| e.is_a?(Hash) ? all_keys(e) : e }
end

Solution

Some notes:

-
The flattening should be performed where the non-desired nesting is being introduced, not later. Use flat_map instead of map:

-
Why e for the value name instead of v?

I'd write:

def all_keys(hash)
  hash.keys + hash.values.flat_map { |v| v.is_a?(Hash) ? all_keys(v) : [v] }
end


Another way to do it, slightly shorter, is to iterate directly the pairs. Pick the one which is more declarative to you:

def all_keys(hash)
  hash.flat_map { |k, v| [k] + (v.is_a?(Hash) ? all_keys(v) : [v]) }
end

Code Snippets

def all_keys(hash)
  hash.keys + hash.values.flat_map { |v| v.is_a?(Hash) ? all_keys(v) : [v] }
end
def all_keys(hash)
  hash.flat_map { |k, v| [k] + (v.is_a?(Hash) ? all_keys(v) : [v]) }
end

Context

StackExchange Code Review Q#120791, answer score: 7

Revisions (0)

No revisions yet.