yerforkferchips yerforkferchips - 6 months ago 69
Ruby Question

Flattening nested hash to a single hash with Ruby/Rails

I want to "flatten" (not in the classical sense of

.flatten
) down a hash with varying levels of depth, like this:

{
:foo => "bar",
:hello => {
:world => "Hello World",
:bro => "What's up dude?",
},
:a => {
:b => {
:c => "d"
}
}
}


down into a hash with one single level, and all the nested keys merged into one string, so it would become this:

{
:foo => "bar",
:"hello.world" => "Hello World",
:"hello.bro" => "What's up dude?",
:"a.b.c" => "d"
}


but I can't think of a good way to do it. It's a bit like the
deep_
helper functions that Rails adds to Hashes, but not quite the same. I know recursion would be the way to go here, but I've never written a recursive function in Ruby.

Answer

You could do this:

def flatten_hash(hash)
  hash.each_with_object({}) do |(k, v), h|
    if v.is_a? Hash
      flatten_hash(v).map do |h_k, h_v|
        h["#{k}.#{h_k}".to_sym] = h_v
      end
    else 
      h[k] = v
    end
   end
end

flatten_hash(:foo => "bar",
  :hello => {
    :world => "Hello World",
    :bro => "What's up dude?",
  },
  :a => {
    :b => {
      :c => "d"
    }
  })
# => {:foo=>"bar", 
# =>  :"hello.world"=>"Hello World", 
# =>  :"hello.bro"=>"What's up dude?", 
# =>  :"a.b.c"=>"d"} 
Comments