jsvisa
jsvisa

Reputation: 3237

What is the difference of Ruby's Array#to_a method

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

Answers (5)

BroiSatse
BroiSatse

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

Andrew Marshall
Andrew Marshall

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

sawa
sawa

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

Arup Rakshit
Arup Rakshit

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

Karthik T
Karthik T

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

Related Questions