6

I have an array in Ruby that consists of 5 empty arrays. I am trying to use the << operator to push a string into the first array, but the result is that the string gets pushed into ALL of the arrays. Please help me understand this.

The expected output is:

# => [["car"], [], [], [], []]

but instead I get:

# => [["car"], ["car"], ["car"], ["car"], ["car"]]

irb dump:

1.9.3-p194 :001 > output = Array.new(5, [])
 => [[], [], [], [], []] 
1.9.3-p194 :002 > output.inspect
 => "[[], [], [], [], []]" 
1.9.3-p194 :003 > output[0].inspect
 => "[]" 
1.9.3-p194 :004 > output[0] << "car"
 => ["car"] 
1.9.3-p194 :005 > output.inspect
 => "[[\"car\"], [\"car\"], [\"car\"], [\"car\"], [\"car\"]]" 
4
  • possible duplicate of Why doesn't terse way of defining new hashes in Ruby work (they all refer to same object) Commented May 31, 2012 at 4:45
  • Thanks all! This was REALLY stumping me. And now I learned a new method: object_id Commented May 31, 2012 at 5:06
  • Can anyone help me understand why this is happening, so I can understand Ruby better? Commented May 31, 2012 at 5:09
  • You are creating five instances of the same [] array, which is why you see duplicates. Commented May 31, 2012 at 5:16

3 Answers 3

6

They're all the same object:

ree-1.8.7-2012.02 :001 > output = Array.new(5, [])
 => [[], [], [], [], []] 
ree-1.8.7-2012.02 :002 > output[0]
 => [] 
ree-1.8.7-2012.02 :003 > output[0].object_id
 => 2219989240 
ree-1.8.7-2012.02 :004 > output[1].object_id
 => 2219989240 
ree-1.8.7-2012.02 :005 > output[2].object_id
 => 2219989240 
ree-1.8.7-2012.02 :006 > output[3].object_id
 => 2219989240 
ree-1.8.7-2012.02 :007 > output[4].object_id
 => 2219989240 
ree-1.8.7-2012.02 :008 > 

Try this:

ree-1.8.7-2012.02 :008 > output = []
 => [] 
ree-1.8.7-2012.02 :009 > 5.times{output << []}
 => 5 
Sign up to request clarification or add additional context in comments.

Comments

5

They all have the same object id, as pointed out by Pedro Nascimento, if the arrays are initialized in that manner. You can get around this by using a similar syntax to create your nested arrays:

irb(main):047:0> output = Array.new(5) {[]}
=> [[], [], [], [], []]
irb(main):048:0> output.each {|i| puts i.object_id}
10941700
10941680
10941660
10941640
10941620

So your append to output[0] will work as expected:

irb(main):049:0> output[0] << "cat"
=> ["cat"]
irb(main):050:0> output
=> [["cat"], [], [], [], []]

Comments

1

The code

output = Array.new(5, [])

is trying to create only one copy of the object,

So

ree-1.8.7-2012.02 :003 > output[0].object_id
 => 2219989240 
ree-1.8.7-2012.02 :004 > output[1].object_id
 => 2219989240 
ree-1.8.7-2012.02 :005 > output[2].object_id
 => 2219989240 
ree-1.8.7-2012.02 :006 > output[3].object_id
 => 2219989240 
ree-1.8.7-2012.02 :007 > output[4].object_id
 => 2219989240 

If you want to create multiple copies of object, use this

     output = Array.new(5) {[]}    #=> [[], [], [], [], []] 

The code

 output.each {|i| puts i.object_id}

will show you

1.9.3-p194 :005 >  output.each {|i| puts i.object_id}
13417360
13417340
13417320
13417300
13417280
 => [[], [], [], [], []] 

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.