scramble cadenza

技術ネタのガラクタ置き場

ruby で 多次元hash の初期化するときの話

each の中とかで、いきなり

h["1"]["2"] = 2

とかやりたいときの話。 Hash.new して上記のようなことをやろうとすると、エラーになってしまう。

rakkyooの備忘録 では以下のような書き方があるよーと紹介されている。

# 2次元ハッシュの初期化
h = Hash.new { |hash,key| hash[key] = Hash.new {} }
# 3次元ハッシュの初期化
h = Hash.new { |hash,key| hash[key] = Hash.new { |hash,key| hash[key] = {} } }

h["1"]["2"]["3"] = 3 # (=> エラーになりません.)

でもこれ、ちとわかりづらい。ただ初期化するだけなのにとても長い。
こんなやり方があります。

#2次元ハッシュの初期化
h = Hash.new( {} ) # Hash#new に空配列を渡す

#3次元ハッシュの初期化
h = Hash.new( Hash.new( {} ) ) # Hash.new したものに、さらに二次元で初期化された hash を渡す

h["1"]["2"]["3"] = 3 # (=> エラーになりません.)

おまけ

別の話になるけれど、初期化せずに以下のように小分けにする方法も合ったりする。
初期化にこだわるのではなく、こちらのやり方で書いてみると、意外とコードがスッキリするときもあるので、メモ。

hash = { }
h = { "2" => 2 }
hash["1"] = h

hash["1"]["2"] #=> 2

応用例

hash = {}.tap do |h|
  h["1"] = { "2" => 2 }
end

hash["1"]["2"] #=> 2