1

I have this piece of code that creates an array of arrays ([[],[],[]]) and an iterator that attempts to populate the respective arrays with numbers (shown below)

array = Array.new(3,[])
10.times do
  array[0] << 2
  array[1] << 3
  array[2] << 4
end

When I execute this code, I expected to see this

[[2,2,2,2,etc....],[3,3,3,3,etc...],[4,4,4,4,4...etc]]

but instead I get this:

[[2,3,4,2,3,4,2,3,4....repeat],[2,3,4,2,3,4,2,3,4....repeat],[2,3,4,2,3,4,2,3,4....repeat]]

I've tried to walk through it with byebug and it makes no sense to me. What is going on here?

1
  • 1
    array.map(&:object_id) can be illuminating. Commented Aug 31, 2016 at 3:44

3 Answers 3

5

Array.new(3, []) is not equivalent to [[],[],[]]. It is equivalent to array = []; [array, array, array], an array of three references to the same array. After array[0] << 2, you have [[2], [2], [2]], because all three elements point at the same array.

What you want is Array.new(3) { [] }, with a block specifying the default; this way, a new [] is created for each element.

Even better, your whole code can be written as:

Array.new(3) { |i| Array.new(10, i + 2) }
Sign up to request clarification or add additional context in comments.

1 Comment

Or even Array.new(3) { |i| [i + 2] * 10 } which is shorter to type and some people may find more intuitive.
1

The initializer you use is meant to be used with immutable objects, like creating an array of n times the same integer. For mutable objects use the block version. Here's the solution to your problem:

array = Array.new(3) { [] }

10.times do
  array[0] << 2
  array[1] << 3
  array[2] << 4
end

array[0]
#=> [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

Comments

1

Read the documentation

The second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.

To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:

Array.new(4) { Hash.new } #=> [{}, {}, {}, {}]

This is also a quick way to build up multi-dimensional arrays:

empty_table = Array.new(3) { Array.new(3) }

Therefore, your code first line should be

array = Array.new(3) { Array.new(3) }

Comments

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.