3

I'm trying to write my own transpose method. I'm wondering how the different forms of concatenation are affecting my code.

multi = [[1,3,5],[2,4,6],[7,9,8]]
new = Array.new(multi.length, [])
multi.each do |c|
    c.each_with_index do |x,y|
        new[y] += [x]
    end
end
new #=> [[1, 3, 5], [2, 4, 6], [7, 9, 8]]

multi = [[1,3,5],[2,4,6],[7,9,8]]
new = Array.new(multi.length, [])
multi.each do |c|
    c.each_with_index do |x,y|
        new[y] << x
    end
end
new #=> [[1, 3, 5, 2, 4, 6, 7, 9, 8], [1, 3, 5, 2, 4, 6, 7, 9, 8], [1, 3, 5, 2, 4, 6, 7, 9, 8]]

Why do they not work in an identical fashion?

Travis
  • 13,311
  • 4
  • 26
  • 40
Chris
  • 391
  • 4
  • 14
  • 2
    Actually, both do not work as transpose. The first one looks like it does because you are using a special example that has the same number of rows and columns. – sawa Oct 12 '15 at 04:16
  • << this will work like appending means new[0] << 1 then new[0] << 3 then new [0] << 5 .... so `new[0] = [1, 3, 5, 2, 4, 6, 7, 9, 8]`... same of – Rajarshi Das Oct 12 '15 at 04:17

1 Answers1

5

With

new = Array.new(multi.length, [])
# => [[], [], []]

the elements in new refer to the same Array objects. Check their id:

new.map {|e| e.object_id}
# => [1625920, 1625920, 1625920]

The first code snippet gives you the expected result because new[y] += [x] assigns to new[y] a new Array object, so each element in new now doesn't refer to the same object:

new.map {|e| e.object_id}
# => [22798480, 22798440, 22798400]

With the second code snippet, each element in new still refers to the original Array object.

sawa
  • 165,429
  • 45
  • 277
  • 381
Yu Hao
  • 119,891
  • 44
  • 235
  • 294