Techioz Blog

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