How to recursively collect deeply nested keys with ruby ​​hash

I'm looking for a clever way to collect the parent keys of a deeply nested key and assign them as value. eg...

take the hash as ...

{
  :foo => {
    :bar => {
      :baz => 'a',
      :bez => 'b',
      :biz => 'c'
    }
  }
}

      

and create a hash from this like this ...

{
  :foo => {
    :bar => {
      :baz => [:foo, :bar, :baz],
      :bez => [:foo, :bar, :bez],
      :biz => [:foo, :bar, :biz]
    }
  }
}

      

+3


source to share


3 answers


Try a recursive solution:



# array of parent keys initially []
def nested(hash, keys = [])
  # go through each key-value pair
  hash.each do |key, val|
    # if the value is a Hash, recurse and
    # add the key to the array of parents
    if val.is_a? Hash
      nested(val, keys.push(key))
      # remove last parent when we're done
      # with this pair
      keys.pop
    else
      # if the value is not a Hash, set the
      # value to parents + current key
      hash[key] = keys + [key]
    end
  end
end

      

+2


source


Make a recursive function.



def recurse(h, acc=[])
  Hash[h.map { |key, value|
    if value.is_a? Hash
      [key, recurse(value, acc + [key])]
    else
      [key, acc + [key]]
    end
  }]
  # You can use h.map {...}.to_h in Ruby 2.1+
end

recurse({
  :foo => {
    :bar => {
      :baz => 'a',
      :bez => 'b',
      :biz => 'c'
    }
  }
})
# =>  {:foo=>
#       {:bar=>
#         {:baz=>[:foo, :bar, :baz],
#                 :bez=>[:foo, :bar, :bez],
#                 :biz=>[:foo, :bar, :biz]}}}

      

+1


source


I suggest the following recursion.

code

def rehash(h, keys = [])
  h.each_with_object({}) { |(k,v),g|
    g[k] = case v
           when Hash then rehash(v, keys+[k]) 
           else           (keys + [k])       
           end
  }
end

      

Example

h = { :foo => {
        :bar => {
          :baz => 'a',
          :bez => 'b',
          :biz => 'c'
        }
      }
    }

rehash(h)  
  #=> {:foo=>
        {:bar=>
          {:baz=>[:foo, :bar, :baz],
           :bez=>[:foo, :bar, :bez],
           :biz=>[:foo, :bar, :biz]}}}

      

+1


source







All Articles