克隆或复制Ruby的Scan方法的结果数组?

时间:2014-03-11 06:37:30

标签: ruby

假设我传递字符串" abcd"使用正则表达式/(a)|(b)/通过Ruby的Scan方法。这将返回一个数组:

>> results_orig = "abcd".scan(/(a)|(b)/)
#=> [["a", nil], [nil, "b"]]

现在,如果我复制(.dup)或克隆(.clone)这个数组,

>> results_copy = results_orig.dup
#=> [[["a", nil], [nil, "b"]]

并修改此副本的任何元素,原始数组也会被修改!

>> results_copy[0][0]="hello"
#=> "hello"
>> results_copy
#=> [["hello", nil], [nil, "b"]]
>> results_orig
#=> [["hello", nil], [nil, "b"]]

这很奇怪,因为首先,数组具有不同的对象ID(results_orig.object_id == results_copy.object_id返回false),其次,如果数组不 Scan方法的产物。要查看后者,请考虑以下示例。

>> a = [1, 2, 3]
>> b = a.dup
>> b[0] = "hello"
>> a
#=> [1, 2, 3]
>> b
#=> ["hello", 2, 3]

我目前的解决方案是运行扫描两次并将每个数组捕获到不同的对象中 - 即r_orig = "abca".scan(/(a)|(b)/)" ; r_copy = "abca".scan(/(a)|(b)/)。但是当我必须扫描数百个字符串时,这将是非常低效的。

是否有正确的方法从Scan的结果复制数组,然后我可以修改,同时保持原始结果数组不受伤害?

编辑#1:我在Mac OS X 10.9.2上运行Ruby 2.0.0-p353。

编辑#2:当阵列结构嵌套时,问题似乎存在...简单(单级)阵列似乎没有这个问题。更正了我的示例以反映这一点。

1 个答案:

答案 0 :(得分:3)

您需要制作一份Deep副本。 Check out this article了解更多信息。基本上,你需要做

copied_array = Marshal.load(Marshal.dump(complex_array))

代码来源:http://thingsaaronmade.com/blog/ruby-shallow-copy-surprise.html。编组适用于数组,但不适用于每个对象。执行Deep副本的更强大的方法是对此question的回答。