Reputation: 3237
For example:
a = [1,2,3,4]
b = a
c = a.to_a
a.insert(0,0) #=> [0,1,2,3,4]
b #=> [0,1,2,3,4]
c #=> [0,1,2,3,4]
Why the output of array b
and c
is the same? If I want to get a copy of array a
, not a reference one, which method should I use?
Upvotes: 2
Views: 463
Reputation: 44715
The reason for that is that variables are merely references to data. Variables are stored in memory; variables keep address of where they are located in a memory. So when you do:
a = b
Those two variables point to the same memory location, hence if you alter a
, b
is altered as well because it is the same object.
There are a few ways to force Ruby to create another copy of the object. The most popular one is the dup
method mentioned by LBg. Note however that it is only creating a shallow copy. If you run:
a = ['foo','bar', []]
b = a.dup
a << 'blah'
b #=> ['foo', 'bar', []] as expected but
b[3] << blah
a #=> ['foobar', 'bar', ['blah]]
The reason for that is that array is in fact an array of references and nested array has not been duplicated when performing dup
, so they are the same object.
To create a deep copy of an object, you can use the Marshall module:
b = Marshal.load(Marshal.dump(a))
However, usually you don't really need to do this. Also, some objects cannot be duplicated (e.g. symbols).
Upvotes: 1
Reputation: 97004
This is because Array#to_a
returns self
, so both variables contain a reference to the same Array object. In order to get a new Array with the same contents, you can use either dup
or clone
(read about the differences between dup
and clone
):
a = [1, 2, 3]
b = a.dup
a << 4
a #=> [1, 2, 3, 4]
b #=> [1, 2, 3]
Note, however, that the same object references are stored in the new array. This means if you mutate the objects themselves they will still change in both arrays:
a = ['foo', 'bar']
b = a.dup
a[0] << 'baz'
a #=> ["foobaz", "bar"]
b #=> ["foobaz", "bar"]
This is because dup
and clone
are shallow-copies.
Upvotes: 2
Reputation: 168249
Array#to_a
returns the receiver. That is why b
and c
refer to the same thing. Regarding why to_a
returns the original array, in principle, it could be defined one or the other way, but I guess one use case for to_a
is to apply it to a variable that is potentially nil
to ensure it becomes an array.
some_value.to_a # => `[]` if `some_value` is `nil`
In such use case, you don't need to replace the array with another one in case the receiver is already an array. That would be performantly more preferable.
Upvotes: 1
Reputation: 118299
Why the output of array b and c is the same?
Because all three local variables referencing the same objects,as below:
a = [1,2,3,4]
b = a
c = a.to_a
a.object_id
# => 72187200
b.object_id
# => 72187200
c.object_id
# => 72187200
If i want to get a copy of array a, not a reference one , which method should i use?
Then use a.dup
.Here documented Object#dup
a = [1,2,3,4]
b = a.dup
c = a.dup
a.object_id
# => 82139270
b.object_id
# => 82139210
c.object_id
# => 82134600
a.insert(0,0) # => [0, 1, 2, 3, 4]
b # => [1, 2, 3, 4]
c # => [1, 2, 3, 4]
Array#to_a
says : Returns self.If called on a subclass of Array, converts the receiver to an Array object.
So it will not be helpful as per your need.
Upvotes: 4
Reputation: 31972
You can just do
b = a.dup
OLD POST
You can try this if there is no easier way
b = a.map {|x| x}
It works
1.9.3-p448 :001 > a = [1,2,3] => [1, 2, 3]
1.9.3-p448 :002 > b = a => [1, 2, 3]
1.9.3-p448 :003 > c = a.map{|x| x} => [1, 2, 3]
1.9.3-p448 :004 > a<<0 => [1, 2, 3, 0]
1.9.3-p448 :005 > b => [1, 2, 3, 0]
1.9.3-p448 :006 > c => [1, 2, 3]
But it is a shallow copy though.
According to this post, a.dup
is the easier way.
Upvotes: 0