Rubyでの多次元配列の操作[重複]
概要
次のコードを使用して初期化した多次元配列があります。
arr = Array.new(3, Array.new(3, "x"))
puts arr.inspect
# Console O/P
# [["x", "x", "x"], ["x", "x", "x"], ["x", "x", "x"]]
上記の配列を操作すると、予期しない応答が返されます。
arr[0][0] = "y"
puts arr.inspect
# Console O/P
# [["y", "x", "x"], ["y", "x", "x"], ["y", "x", "x"]]
更新の正確な次元を指定したのに、配列内の複数のエントリが更新される理由がわかりません。
Array#initialize ドキュメントを参照しています。
上記の実装とは異なり、この方法で配列を初期化して操作しようとすると、期待どおりの応答が得られます。
arr = Array.new(3) { Array.new(3) { "x" } }
arr[0][1] = "y"
puts arr.inspect
# Console O/P
# [["x", "y", "x"], ["x", "x", "x"], ["x", "x", "x"]]
ここでも、実装が上記の初期化と異なる理由がわかりません。
私の理解によれば、上記のドキュメントで述べた 2 つの初期化の違いは次のとおりです。
#new(size, default_value) ⇒ Object
#new(size) {|index| ... } ⇒ Object
両方の配列が同じように動作することが期待されます。
解決策
違いは、最初のバージョンでは、各「行」にまったく同じ配列が再利用されることです。したがって、その配列内の値の 1 つを変更すると、それは同じ配列であるため、すべての行の配列が変更されます。
arr = Array.new(3, Array.new(3, "x"))
arr.map(&:object_id)
#=> [31740, 31740, 31740] # All arrays are the same object
ただし、2 番目のバージョンでは、行ごとに新しい配列が作成されるため、1 つのエントリを変更しても、他の配列のエントリは変更されません。
arr = Array.new(3) { Array.new(3) { "x" } }
arr.map(&:object_id)
#=> [81520, 81540, 81560] # Each array is a different instance