RubyのHashは、値をセットしていないkeyの値を取得しようとするとnil
が返るが、 Hash.new(x)
を使うことでデフォルト値を任意の値に変更できる。
a = {}
p a #=> {}
p a[:x] #=> nil
b = Hash.new(0)
p b #=> {}
p b[:h] #=> 0
b[:i] += 1
b[:j] += 2
p b #=> {:i => 1, :j => 2}
しかし、デフォルト値を破壊的に変更してしまうと、予測とは違う動きをするので注意しなければいけない。
x = Hash.new([])
p x #=> {}
x[:p] << 1
x[:q] << 2
p x #=> {} え?????
x[:r] =x[:r] << 3
p x #=> {:r=>[1, 2, 3]} ?!?!?!?
x[:s] = x[:s]
p x #=> {:r=>[1, 2, 3], :s=>[1, 2, 3]} !!?!!??!!???
Hashのデフォルト値を空にして、特定のkeyにどんどん値を追加していきたい、ということはよくありそうだ。
そういう場合、newのブロックを使い以下のようにするといい。
h = Hash.new{[]}
h[:x] += [1]
h[:x] += [2]
h[:y] += [3]
h[:y] += [4]
p h #=> {:x=>[1, 2], :y=>[3, 4]}
Arrayオブジェクトを毎回新しく作るのはパフォーマンスがーー! と思うなら以下のようになるといいのかもしれない。
h = Hash.new{|hash, key| hash[key] = []}
h[:x] << 10
h[:x] << 20
h[:y] << 30
h[:y] << 40
p h #=> {:x=>[10, 20], :y=>[30, 40]}
最初、Rubyのバグか? と思ったけど、普通に仕様らしい。
ちゃんと読んだことなかったけど、リファレンスに載ってた。