simanのブログ

ゆるふわプログラマー。競技プログラミングやってます。Ruby好き

Rubyで二次元配列の初期化

Rubyで二次元配列を初期化するときは注意が必要です。


3x3の2次元配列を作るときのよくある間違い

a = Array.new(3, Array.new(3, 0))

これで配列の初期化が出来たと思うのですが、実は出来ていません。実際に配列の状態を変更してみると明らかになります。


a = Array.new(3, Array.new(3, 0))

p a
a[0][0] = 5
p a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[5, 0, 0], [5, 0, 0], [5, 0, 0]]

実行結果から第一要素の配列に対して行った操作が他の要素に影響を及ぼしていることがわかります。これは、最初の初期化で別々の配列オブジェクトを定義したつもりが、実は全て同じ配列オブジェクトを参照しているからです。


a = Array.new(3, Array.new(3, 0))

p a.map(&:object_id)
[70285890080600, 70285890080600, 70285890080600]

なので、別々のオブジェクトとして定義するには別の初期化の方法を行う必要があります。


・二次元配列の初期化の方法

別々のオブジェクトとして初期化するには色々な方法があるのですが、ここでは Array.new にブロックを渡す方法を紹介します。

a = Array.new(3) { Array.new(3,0) }

p a
a[0][0] = 5
p a
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[5, 0, 0], [0, 0, 0], [0, 0, 0]]

別々のオブジェクトとして定義したので、他の要素に影響を与えていないことがわかります。


a = Array.new(3) { Array.new(3, 0) }

p a.map(&:object_id)
[70224619687520, 70224619687500, 70224619687480]

Rubyでは二次元配列の初期化と複製に注意が必要です。