Ruby の Hash の第一引数のデフォルト値の設定では、破壊的操作をよく行うクラスをセットすると罠にはまります。みんな一度ははまります。
$ pry
[1] pry(main)> h = Hash.new([])
=> {}
[2] pry(main)> h[:a] << 1
=> [1]
[3] pry(main)> h[:b] += [1]
=> [1, 1]
[4] pry(main)> h.keys
=> [:b]
[5] pry(main)> h[:a]
=> [1]
この挙動に何故なるか、理解できる人は手を上げてください!はいあまりいませんね。
なぜこんな挙動になるか、詳しくは以下。
というわけで、デフォルト値の挙動をしっかりと把握してないとはまる人が出てくるので、しっかりと
Hash.new {|h, k| h[k] = [] }
と書くようにしましょう。なお破壊的操作が行われない、例えば Fixnum などは
Hash.new(0)
で問題ないですが、複数人の開発で上記コードが何故問題無いか、を理解してない人が居る可能性がある場合(ほとんどの場合居ます)、へ〜 Hash.new(object)
って書けるんだ便利、と理解され、破壊的操作が可能なオブジェクトを突っ込んで問題が起きる(複数回経験アリ)ので、
Hash.new {|h, k| h[k] = 0 }
と冗長でも心がけた方が良いです。