Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a hash into a nested hash

Tags:

ruby

hash

nested

This question is the inverse of this question.

Given a hash that has an array for each key like

{
    [:a, :b, :c] => 1,
    [:a, :b, :d] => 2,
    [:a, :e] => 3,
    [:f] => 4,
}

what is the best way to convert it into a nested hash like

{
    :a => {
       :b => {:c => 1, :d => 2},
       :e => 3,
    },
    :f => 4,
}
like image 586
sawa Avatar asked Dec 06 '11 18:12

sawa


2 Answers

Here's an iterative solution, a recursive one is left as an exercise to the reader:

def convert(h={})
  ret = {}
  h.each do |k,v|
    node = ret
    k[0..-2].each {|x| node[x]||={}; node=node[x]}
    node[k[-1]] = v
  end
  ret
end

convert(your_hash) # => {:f=>4, :a=>{:b=>{:c=>1, :d=>2}, :e=>3}}
like image 61
maerics Avatar answered Sep 18 '22 02:09

maerics


Functional recursive algorithm:

require 'facets'

class Hash
  def nestify
    map_by { |ks, v| [ks.first, [ks.drop(1), v]] }.mash do |key, pairs|
      [key, pairs.first[0].empty? ? pairs.first[1] : Hash[pairs].nestify]
    end
  end
end

p {[:a, :b, :c]=>1, [:a, :b, :d]=>2, [:a, :e]=>3, [:f]=>4}.nestify
# {:a=>{:b=>{:c=>1, :d=>2}, :e=>3}, :f=>4}
like image 30
tokland Avatar answered Sep 20 '22 02:09

tokland