ハッシュ要素の配列、配列要素のハッシュ、配列要素の配列、ハッシュ要素のハッシュ

'14/5/4追記:すみません初級だと思っていた方法と検証方法が間違っていましたorz 確認し直します。

初級:ハッシュ要素の配列 Array.new(n) { {} }(n:要素数Array.new{ {} }([{}]でもOK)

初級:配列要素のハッシュ Hash.new { |h, k| h[k] = } Hash.new{ }({[]}はNG!)

中級:配列要素の配列 Array.new(n) { [] }(n:要素数

同じ配列を参照した配列を作ってしまうことがよくあるので注意。

3x3の2次元配列を作るときのよくある間違い
a = Array.new(3, Array.new(3, 0) )
これで配列の初期化が出来たと思うのだが、これは間違い。

a = Array.new(3, Array.new(3, 0) )
p a # => [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
a[0][0] = 5
p a # => [[5, 0, 0], [5, 0, 0], [5, 0, 0]]

これは、最初の初期化で別々の配列オブジェクトを定義したつもりが、実は全て同じ配列オブジェクトを参照しているからである。
Rubyで二次元配列の初期化 - simanのブログ

singleton method Array.new

new(size = 0, val = nil) -> Array
長さ size の配列を生成し、各要素を val で初期化して返します。
要素毎に val が複製されるわけではないことに注意してください。 全要素が同じオブジェクト val を参照します。
new(size) {|index| ... } -> Array
長さ size の配列を生成し、各要素のインデックスを引数としてブロックを実行し、 各要素の値をブロックの評価結果に設定します。
http://rurema.clear-code.com/1.9.3/method/Array/s/new.html

pry(main)> aa = Array.new(3) { Array.new }
=> [[], [], []]
pry(main)> aa[2][2] = 4
=> 4
pry(main)> aa[2][5] = 10
=> 10
pry(main)> aa[1][3] = 3
=> 3
pry(main)> aa[3][3] = 9
NoMethodError: undefined method `[]=' for nil:NilClass
pry(main)> aa
=> [[], [nil, nil, nil, 3], [nil, nil, 4, nil, nil, 10]]

上記ではn=3としているので配列の第1添字は(0..n-1)つまり(0..2)になります。でも第2添字は0以上の整数であればOKです。
なお、Array.new(n) { Array.new }の代わりに

  • Array.new(n).map { Array.new }(mapの代わりにmap!も)
  • arr = Array.new(n); arr.each_index { |y| arr[y] = Array.new }

などのやり方もWebに挙がっていますが、Array.new(n) { Array.new }が一番スマートだと思います。

上級:ハッシュ要素のハッシュ Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) }

無限に深いハッシュ要素が自動生成されます。
2段階(ハッシュのハッシュ)でよければHash.new { |h, k| h[k] = {} }でも大丈夫です。
3段階(ハッシュのハッシュのハッシュ)でよければHash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } }で(以下同文

前置き

singleton method Hash.new

new(ifnone = nil) -> Hash
空の新しいハッシュを生成します。ifnone はキーに対 応する値が存在しない時のデフォルト値です。設定したデフォルト値はHash#defaultで参照できます。
new {|hash, key| ... } -> Hash
空の新しいハッシュを生成します。ブロックの評価結果がデフォルト値になりま す。設定したデフォルト値はHash#default_procで参照できます。

# ブロックを与えると、対応する値がまだ無いキーが呼び出される度に
# ブロックを評価するので、全て別のオブジェクトになります。
h = Hash.new {|hash, key| hash[key] = "foo"}
p h[1]                  #=> "foo"
p h[1].object_id        #=> 6126900
p h[1] << "bar"         #=> "foobar"
p h[1]                  #=> "foobar"
p h[2]                  #=> "foo"
p h[2].object_id        #=> 6126840
p h                     #=> {1=>"foobar", 2=>"foo"}

singleton method Hash.new (Ruby 1.9.3)

instance method Hash#default

default -> object | nil
default(key) -> object | nil
ハッシュのデフォルト値を返します。
ハッシュのデフォルト値がブロックで与えられている場合、 1 番目の形式だと 返り値が nil になることに注意してください。この場合、ハッシュのデフォルト値に ついて調べるには 2 番目の形式か Hash#default_proc を使ってください。

instance method Hash#default_proc

default_proc -> Proc | nil
ハッシュのデフォルト値を返す Proc オブジェクトを返します。 ハッシュがブロック形式のデフォルト値を持たない場合 nil を返します。
instance method Hash#default_proc (Ruby 1.9.3)

本編

rubyオンラインマニュアルに

値が設定されていないハッシュ要素を参照するとその都度ブロックを実行し、その結果を返します。ブロックにはそのハッシュとハッシュを参照したときのキーが渡されます。

とあります。
つまり
my_hash = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) }
my_hash[:aaa] = 'bbb'
とした時点で、
my_hash[:aaa] = Hash.new()
my_hash[:aaa] = 'bbb'
もやってくれるし、さらに一階層深いハッシュが作られた場合にHash.new()をする準備、例えば以下のようなこと
my_hash[:aaa][:aaa2] = Hash.new()
をしてくれる準備も整ってるよ、という状態になります。
参考サイト

Ruby On Rails ピチカート街道 - rubyでハッシュのハッシュのハッシュとかを簡単に作る方法 -