1

I am facing something i do not fully understand.

I have an array whose elements are arrays.

So I have two nested loops, in the inner loop I fill my inner array then in the outer loop i fill the outer array with the inner array.

arr=[]
mat=[]
for m in (0..1)
  for k in (0..1)
    arr[k]=rand.to_s
  end
  mat[m]=arr
end

At the end my matrix is filled with two array; each array contains the values calculated in the last iteration. If i want the first element in matrix to contain the first computed array I have to reinitialize the arr object at each loop. So it seems that assignment is made by reference until the arr object is "cleaned". If I add

mat[m]=arr
arr=[]

all works as expected: mat[0] will contain the array computed in the first loop, and mat[1] will contain the array computed in the second loop.

Is this by design or is it an undesired side effect? This is happening only if I assign arrays as array elements. If if fill an array with simple string variables in a loop all goes as expected.

I know that it is good programming practice to avoid reusing objects, but this behavior is anyway strange.

3 Answers 3

4

Your problem is that your arr variable's contents is being overwritten with each iteration: the arr[k] overwrites whatever is in there already. The arr variable needs to be local to the block instead:

mat = []
2.times do             # avoid for... use iterators instead
  row = []
  2.times do 
    row << rand.to_s
  end
  mat << row
end
Sign up to request clarification or add additional context in comments.

5 Comments

@Niel: That was more or less what I meant, actually. My non-native English might be getting in the way though. ;-) I've rephrased it in a hopefully better way.
Yes I think it is good enough now that I deleted my comment and +1-ed
@Denis: Thanks, i already found that this is the way it works. The question is if it is correct. I expect that each time I do mat << row , a copy of row is added as a new element of mat. This happens only if row is re-initialzied at each iteration. Otherwise mat is added with a pointer to row, not with is content. Am I wrong?
@Denis: Maybe now I got it. It is a matter of variable scoping. It is wrong to declare row outside of both loops.
@kranz: yeah, your specific issue was scoping. Regarding what gets added in mat = or mat[m] =, you're always adding pointers to objects. Without the proper scope, you'd end up referencing the same row twice, and you can see that by running it through pretty print.)
0

I like the approach of using hashes instead of multidimensional arrays.

How about this:

def creat­e_matrix x, y, conte­nt = nil, &block
  rows = (0...x­).to_a
  cols = (0...y­).to_a
  indices = rows.­product cols
  matrix = {}
  indices.ea­ch { |inde­x| matri­x[index] = ( block­_given? ? yield­( index ) : conte­nt ) }
  matrix
end

Then do:

matrix = create_matrix( 2, 2 ) { rand.to_s }

You will get a hash, that you can access like this:

matrix[[0, 1]] #note the double brackets

Comments

0

Another way of doing it:

(1..4).map{rand}.each_slice(2).to_a

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.