设置一个等于另一个的数组,然后更改第一个数组而不影响第二个数组

时间:2014-01-19 11:01:34

标签: ruby arrays

我有一个数组'a',后来我设置了一个新数组'b'等于'a'。当我从任一数组中删除一个元素时,它们都会更改而不是显式引用的数组。我认为这是因为他们指向同一个底层对象?

a= ["cat","hat","dog"]
b= a
a.delete_at(0)
print a
>> a = ["hat","dog"
print b
>> b = ["hat","dog"]

如何设置两个相等的变量,但允许它们独立于以后的操作?我正在寻找这样的行为:

a= ["cat","hat","dog"]
b= a
a.delete_at(0)
print a
>> a = ["hat","dog"
print b
>> b = ["cat","hat","dog"]

2 个答案:

答案 0 :(得分:3)

使用Object#dup创建原始数组的副本:

a = ["cat","hat","dog"]
b = a.dup # b now points to a duplicate of a, not a itself

b # => ["cat","hat","dog"]
b.delete_at(0)

b # => ["hat","dog"]
a # => ["cat","hat","dog"]

验证此行为:

a = [1, 2, 3]
b = a
a.object_id == b.object_id # => true, a and b point to the same objects

a = [1, 2, 3]
b = a.dup
a.object_id == b.object_id # => false, a and b point to different objects

答案 1 :(得分:0)

或许值得注意的是,如果

a = [["cat", "pig"], "hat", "dog"] # => [["cat", "pig"], "hat", "dog"]
b = a.dup                          # => [["cat", "pig"], "hat", "dog"]

然后

a[0].delete_at(0)
a                                  # => [["pig"], "hat", "dog"] 
b                                  # => [["pig"], "hat", "dog"]

在这里你需要这样做:

a = [["cat", "pig"], "hat", "dog"]
b = a.dup 
b[0] = a[0].dup
a[0].delete_at(0)
a                                  # => [["pig"], "hat", "dog"] 
b                                  # => [["cat", "pig"], "hat", "dog"] 

现在假设a要复杂得多,比如一组哈希值,它们的值是哈希数组。显然,必须注意制作a的副本,该副本不会被删除a的深层嵌套元素所影响。你想要的是一个“深层复制”,而不是Object#dupObject#clone所做的“浅层”复制。

幸运的是,使用Marshal#dumpMarshal#load可以轻松制作任何对象的深层副本:

b = Marshal.load(Marshal.dump(a))
a[0].delete_at(0)
a                                  #  => [["pig"], "hat", "dog"]
b                                  #  => [["cat", "pig"], "hat", "dog"]

除此之外,Marshal还用于将对象保存到文件以供以后检索:

File.open('myfile', 'w+') do |f|  
  Marshal.dump(a, f)  
end  

File.open('myfile') do |f|  
  c = Marshal.load(f)  
end  
c                                  #  => [["cat", "pig"], "hat", "dog"]

提醒一句:Marshal文件在所有版本的Ruby中都不可移植。