English

多重配列の初期化

PBM の画像データを 2 重配列で 受けて, 処理しようと思いました. 2 重配列の初期化はどうやろうと考えて, 最初に思いついたのが, これ.

ar = Array.new(4, Array.new(0, 4))

4 x 4 の配列を 0 で初期化したつもり. 1 行で書けて, スマート :-) で も, その後にいろいろ処理して, できた画像を見てみると, 何か変 (T_T) 例 えば…

$ irb 
irb(main):001:0> ar = Array.new(4, Array.new(4, 0))       # initialization
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
irb(main):002:0> ar[1][1] = 2                             # substitution
2
irb(main):003:0> p ar
[[0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0]]  # ??
nil

というように, ar[1][1] = 2 によって ar[1] という配列しか変更していないつもりなのに, 全部の配列が同じように変化し ています.

しばらく理由がわからなかった (^^; のですが, 答えは Ruby FAQ 2.12 にありました. つまり, 配列 ar の全ての要素は, 同一オ ブジェクト (Array.new(4, 0)) を指しているので, 1 つの要素 に対する操作でも, 全ての要素にその影響が出ているように見えてしまいます.

これを回避するには, 配列 ar の全ての要素が互いに異なる 配列を指すように初期化する. 例えば…

$ irb 
irb(main):001:0> ar = Array.new(4).collect { Array.new(4, 0) } # init
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
irb(main):002:0> ar[1][1] = 2
2
irb(main):003:0> p ar
[[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] # seems good
nil

でも用途によっては mdarray を使うほうが, はるかに楽. 初期化のときに指定した範囲の外へアクセスすると, 例外にして くれますし.



[うさぎ印] おたより, お待ちしています

sato.mshr@gmail.com