EvilTester EvilTester - 5 months ago 24
Ruby Question

Ruby appending to arrays

In the following lines of code, the outcome I was expecting is different from the actual result. Can someone help me understand why?

array1 = [["a", "b", "c"], ["a", "b", "c"]]
temp1 = ["x", "y", "z"]
array1 << temp1

2.times do
temp1[0] = gets.chomp #first loop enter 1 and then 4
temp1[1] = gets.chomp #first loop enter 2 and then 5
temp1[2] = gets.chomp #first loop enter 3 and then 6
puts temp1.inspect
array1 << temp1
puts array1.inspect
# Actual result: [["a", "b", "c"], ["a", "b", "c"], ["4", "5", "6"], ["4", "5", "6"], ["4", "5", "6"]]
# Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]
end

Answer

Do this and it will work (add .clone to all references to temp1):

 array1 = [["a", "b", "c"], ["a", "b", "c"]]
 temp1 = ["x", "y", "z"]
 array1 << temp1.clone
 2.times do
      temp1[0] = gets.chomp      #first loop enter 1 and then 4
      temp1[1] = gets.chomp      #first loop enter 2 and then 5
      temp1[2] = gets.chomp      #first loop enter 3 and then 6

      puts temp1.inspect
      array1 << temp1.clone
      puts array1.inspect 

 end

 # Actual result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]

 # Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]

Basically, when you append temp1 in array1 it occurs by reference rather than by value. So whenever the temp1 will be updated, the corresponding appended entry in array1 will also be automatically updated. To prevent this behaviour you need to clone / dup the object before appending it to the array. clone / dup duplicate the object (so it doesn't have same reference / object_id) and then assigns it.

For a detailed explanation check this post.