Rubyでの多次元Hashの作成法

あるいは深さを指定したツリーの作成法。

なんかセオリーがあるのかなと思って探してみたけど、次元数が可変な作成方法は見つからなかった。
試行錯誤しながら作ってたらなんか結構短くなったので公開。

dimension = 3

nodes = []
nodes << {} # 末端Hash
(dimension-1).times do
  node = nodes.shift
  nodes << Hash.new{ |hash, key| hash[key] = node.dup }
end

tree = nodes.shift

使用例

tree[:a][:a][:a] = :aaa
p tree # {:a=>{:a=>{:a=>:aaa}}}

tree[:a][:a][:b] = :aab
p tree # {:a=>{:a=>{:b=>:aab, :a=>:aaa}}}

tree[:a][:b][:a] = :aba
p tree # {:a=>{:b=>{:a=>:aba}, :a=>{:b=>:aab, :a=>:aaa}}}

各ノードは単なるHashなので他のオブジェクトで上書き可能

tree[:b][:a] = :ba
p tree # {:b=>{:a=>:ba}, :a=>{:b=>{:a=>:aba}, :a=>{:b=>:aab, :a=>:aaa}}}

だからってこんな代入すると無限ループになるよ

tree[:a][:b][:b] = tree[:b]
tree[:b][:b][:b] = tree[:a]
p tree # {:b=>{:b=>{:b=>{:b=>{:b=>{...}, :a=>:aba}, :a=>{:b=>:aab, :a=>:aaa}}}, :a=>:ba}, :a=>{:b=>{:b=>{:b=>{:b=>{...}}, :a=>:ba}, :a=>:aba}, :a=>{:b=>:aab, :a=>:aaa}}}