Understanding array.clear

I was working a project Euler problem and noticed that when I used this
code:

array1 = [“a”, “b”, “c”, “d”, “e”]
array2 = Array.new
array2 << array1
array1.clear
p array2

[[]] is my output. But, when I tried:

array1 = [“a”, “b”, “c”, “d”, “e”]
array2 = Array.new
array2 << array1
array1 = []
p array2

[[“a”, “b”, “c”, “d”, “e”]] is my output. I am not understanding why
clearing array1 is changing array2, but replacing the value of array1 is
having no effect.

(btw, using ruby 1.9.2p180)

On Mon, Dec 19, 2011 at 12:48 PM, Nick S. [email protected]
wrote:

I was working a project Euler problem and noticed that when I used this
code:

array1 = [“a”, “b”, “c”, “d”, “e”]
array2 = Array.new
array2 << array1

You just stored the object array1 inside of array 2.

array1.clear

Having cleared array1 (emptied it out) by calling the Array instance
in array1’s clear method…

p array2

[[]] is my output. But, when I tried:

…you see the expected output, since the array1 object is now empty.

array1 = [“a”, “b”, “c”, “d”, “e”]
array2 = Array.new
array2 << array1
array1 = []

Here you are NOT clearing out array1, but assigning a brand new array
object to the variable array1. So the old array1 is still in
existence (and still stored in array2).

p array2

[[“a”, “b”, “c”, “d”, “e”]] is my output. I am not understanding why
clearing array1 is changing array2, but replacing the value of array1 is
having no effect.

I hope this clears it up a bit.

<>

Aaron out.

On 20/12/11 08:48, Nick S. wrote:

(btw, using ruby 1.9.2p180)

So what is happening can be seen by inspecting object ids. In the first
instance we create two new arrays which are referenced by variables
array1 and array2 respectively.

1.9.2p290 :001 > array1 = [“a”, “b”, “c”, “d”, “e”]
=> [“a”, “b”, “c”, “d”, “e”]
1.9.2p290 :002 > array1.object_id
=> 4320500
1.9.2p290 :003 > array2 = Array.new
=> []
1.9.2p290 :004 > array2.object_id
=> 4205400

We then add the array which is referenced by array1 as the first element
of array2

1.9.2p290 :005 > array2 << array1
=> [[“a”, “b”, “c”, “d”, “e”]]
1.9.2p290 :006 > array2.first.object_id == array1.object_id
=> true

So in fact array2 now contains a reference to array1. This then does
what we expect when the array referenced by array1 is cleared. You will
notice the object reference remains the same.

1.9.2p290 :007 > array1.clear
=> []
1.9.2p290 :008 > array2
=> [[]]
1.9.2p290 :009 > array2.first.object_id == array1.object_id
=> true

Now what happens if we do the same thing, except instead of clearing the
array referenced by array1, we assign a new array to array1.

1.9.2p290 :010 > array1 = [“a”, “b”, “c”, “d”, “e”]
=> [“a”, “b”, “c”, “d”, “e”]
1.9.2p290 :011 > array1.object_id
=> 5232600
1.9.2p290 :012 > array2 = Array.new
=> []
1.9.2p290 :013 > array2.object_id
=> 5189800
1.9.2p290 :014 > array2 << array1
=> [[“a”, “b”, “c”, “d”, “e”]]
1.9.2p290 :015 > array2.first.object_id == array1.object_id
=> true
1.9.2p290 :016 > array1 = Array.new
=> []
1.9.2p290 :017 > array2.first.object_id == array1.object_id
=> false
1.9.2p290 :018 > array2
=> [[“a”, “b”, “c”, “d”, “e”]]

As you can see here, when array1 is told to reference a new array, the
array it used to reference is still intact and remains in existence due
to array2 still holding a reference to it. The variable array1 now
points to a shiny new array and thus methods called via array1 are no
longer received by the one we shoved into array2.

1.9.2p290 :019 > array1.object_id
=> 5144400
1.9.2p290 :020 > array2.object_id
=> 5189800
1.9.2p290 :021 > array2.first.object_id
=> 5232600

Does that help?

Sam

Sam and Aaron,
Thank you both. Your explanations have completely “cleared” this up for
me. I had not thought to check the object ID’s.

Vimal,
Thanks for showing me a great use for #dup.

Hi Nick,

In your array2 << array1 statement, generally array2 object refers the
object of array1. So that when you clear array1, the value in the
referred object also gets cleared.

To avoid this, we can use dup method.

Try this:
a = [1, 2, 3, 4, 5]
b = Array.new
b << a.dup
a.clear
p b

will give you [[1, 2]].

Hope it helps you.

Cheers,
Vimal

Hi Nick,

Sorry I did a typo mistake in my reply. The result of the dup should be
like this [[1, 2, 3, 4, 5]].

Cheers,
Vimal