1

An empty array is defined outside a block and within the block, it is assigned to a new variable. If the new array changes, the empty array also modifies its values. Why?

# THIS CODE CHECK WHICH LETTERS IN klas APPEAR IN docs
klas = ["a", "b", "c"]

docs = [[1, "a"], [2, "a"], [3, "b"], [4, "b"], [5, "c"], [6, "c"]]

output = []
empty_array = Array.new(klas.size) { 0 } # EMPTY ARRAY DEFINED HERE

docs.each do |doc|
    puts empty_array.inspect
    puts (output_row = empty_array).inspect # EMPTY ARRAY ASSIGNED TO ANOTHER

    # FIND INDEX OF THE LETTER IN klas FROM docs. ASSIGN 1.
    output_row[klas.index(doc[1])] = 1 # PROBLEM! THIS ALSO CHANGES THE EMPTY ARRAY VALUES
    output << output_row
end

CONSOLE OUTPUT to show empty array changing its value based on another array

###
empty_array is [0, 0, 0]
output_row is [0, 0, 0]
---
###
empty_array is [1, 0, 0]
output_row is [1, 0, 0]
---
###
empty_array is [1, 0, 0]
output_row is [1, 0, 0]
---
###
empty_array is [1, 1, 0]
output_row is [1, 1, 0]
---
###
empty_array is [1, 1, 0]
output_row is [1, 1, 0]
---
###
empty_array is [1, 1, 1]
output_row is [1, 1, 1]
---

# INCORRECT output IS
=> [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]
# SHOULD BE
=> [[1, 0, 0], [1, 0, 0], [0, 1, 0], [0, 1, 0], [0, 0, 1], [0, 0, 1]]

But if the empty array is defined within the block and assigned to a new variable it works as expected.

docs.each do |doc|
    empty_array = Array.new(klas.size) { 0 } # THIS MAKES SURE empty_array stays with zero values
    output_row = empty_array    
    output_row[klas.index(doc[1])] = 1
    output << output_row
end

CORRECT output IS
=> [[1, 0, 0], [1, 0, 0], [0, 1, 0], [0, 1, 0], [0, 0, 1], [0, 0, 1]]

Why is the empty array modifying its value when it is outside a block? Shouldn't it remain the same irrespective of another array changing its value?

1
  • 2
    "Shouldn't it remain the same irrespective of another array changing its value?" – There is no "another array". How many arrays did you create in that piece of code? One. Not two. Commented Aug 8, 2017 at 12:21

1 Answer 1

4

By using

output_row = empty_array

you are not copying the empty array. You are creating a reference to the same underlying array that is referenced in empty_array.

You can create a clone or a duplicate of the array. So use:

output_row = empty_array.dup

This will create a new Array, which is a duplicate of empty_array, see http://ruby-doc.org/core-2.4.1/Object.html#method-i-dup

A more complete explanation on what happens with an example:

a = [1] => [1] # is creating a new array 'x'
               # a is referencing this array, a is not the array itself!

b = a   => [1] # b now references the array 'x'

a = [2] => [2] # is creating a new array 'y', a is referencing this new array
               # the reference of b is not changing

b       => [1] # b still pointing to array 'x'

So with b = a you just tell them to reference the same array x, but b is not a reference to a.

Sign up to request clarification or add additional context in comments.

11 Comments

To check that suspicion I had tried this before posting irb(main):562:0> a = [1] => [1] irb(main):563:0> b = a => [1] irb(main):564:0> a = [2] => [2] irb(main):565:0> b => [1] irb(main):566:0> b = [3] => [3] irb(main):567:0> a => [2]
But if its an array of more elements, a = [0,0,0] it changes it's value, like in the question. But by using dup as you suggested, it works as expected. Why is that? And why with simple values it does not behave differently?
@arjun, I updated my answer. The problem is that you are misunderstanding as the variable a being the array, but a just points to an array, that exists somewhere in the memory. Have a look at my updated answer.
"Any change of one will be reflected in the other" – that sounds like there were two arrays which are being synchronized.
@Stefan Thanks, I edited that out. That part of the answer was written, before I fully understood what I was explaining :-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.