Search code examples
rubyruby-hash

Better way to initialize and update deeply nested Hash


I have a Hash and I want to insert some data into it at a deep level, but a key might be missing at any level. So, I am conditionally initializing it before updating its value at every level.

What would be a better way to write this or an approach that can make code less ugly?

data[:foo] ||= {}
data[:foo][:bar] ||= {}
data[:foo][:bar][:baz] ||= []
data[:foo][:bar][:baz] << 99

Solution

  • Use hash autovivification:

    data = Hash.new { |h, k| h[k] = h.dup.clear }
    #⇒ {}
    
    # or, credits to @Amadan:
    data = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
    #⇒ {}
    
    data[:foo][:bar][:baz] = 42
    data
    #⇒ {:foo=>{:bar=>{:baz=>42}}}
    

    The trick used here is we use Hash#default_proc to create nested keys.

    For your case:

    (data[:foo][:bar][:baz] = []) << 99