多重配列のdeep copy

Rubyの配列をそのまま代入"="するだけだとメモリの参照先が同じなので同じ値しか返ってきません。
また、.dupや.cloneを使っても多重配列はダメみたいです。浅いコピーなので。。。
そこで配列の深いコピー(deep copy)する方法をメモします。

array2 = Marshal.load(Marshal.dump(array1))
  • ダメなパタン
array1 = [[1,2,3],[4,5,6],[7,8,9]]

array3 = array1       # 参照先は同じ
array4 = array1.dup   # オブジェクトはコピーされない
array5 = array1.clone # オブジェクトはコピーされない


array1[1][1] = 10

p array1 # <= [[1, 2, 3], [4, 10, 6], [7, 8, 9]]
p array3 # <= [[1, 2, 3], [4, 10, 6], [7, 8, 9]]
p array4 # <= [[1, 2, 3], [4, 10, 6], [7, 8, 9]]
p array5 # <= [[1, 2, 3], [4, 10, 6], [7, 8, 9]]


ちなみに、Marshal(マーシャリングライブラリ)は、Rubyのオブジェクト(+子孫)をバイナリストリームに変換するためのもの、らしいです。

  • Marshal.dumpは、オブジェクトとその子孫オブジェクトをバイナリストリームに変換
  • Marshal.loadは、バイナリデータをRubyオブジェクトに変換する

うむ、なるほど。"オブジェクトとその子孫"ってところがdeep copyに該当してそうですね。

参考

  • Ruby逆引きハンドブック,るびきち著,C&R研究所 pp.183-184
  • プログラミングRuby1.9 ライブラリ編,Dave Thomas,with Chad Flowler and Andy Hunt著,Ohmsha,pp.138-139