Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of Arrays in ruby, passed by reference

I'm trying to create a 5x5 matrix in Ruby filled with zeroes. The code I used was:

ruby-1.9.2-p290 :014 > a = Array.new(5, Array.new(5, 0))
 => [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] 

However, the newly created arrays inside are not separate objects, but a reference to one. So when I try to do the following: a[2][2] = 1 I get:

=> [[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]] 

Which is obviously not what I want. Checking objects ids confirms it:

ruby-1.9.2-p290 :020 > a.collect {|z| z.__id__}.uniq
 => [70253724580020] 

My questions is: is it a bug or feature? :) And how should I create array of arrays properly?

like image 548
ajgon Avatar asked Dec 07 '22 17:12

ajgon


2 Answers

I'm trying to create a 5x5 matrix in Ruby filled with zeroes. The code I used was:

As others have pointed out, this is how arrays are supposed to work. Instead, you should use the block initializer:

a = Array.new(5) { Array.new(5, 0) }

In addition, however, if you're making a matrix, consider using the Matrix class in the standard library:

require 'matrix'
 # => true 

m = Matrix.build(5, 5) { 0 }
 # => Matrix[[0, 0, 0, 0, 0],
 #           [0, 0, 0, 0, 0],
 #           [0, 0, 0, 0, 0],
 #           [0, 0, 0, 0, 0],
 #           [0, 0, 0, 0, 0]] 

m.determinant
 # => 0 
like image 81
John Feminella Avatar answered Dec 20 '22 23:12

John Feminella


Actually it is a feature.

[...] it is created with size copies of obj (that is, size references to the same obj) [...]

To create distinct arrays you can use e.g.

a = Array.new(5){Array.new(5, 0)}

or

a = (1..5).map{Array.new(5, 0)}
like image 23
Howard Avatar answered Dec 20 '22 23:12

Howard