Two deminsional array assignment issue

Hello,
I’m puzzled with the outcome of this simple code.
The intention is to assign a unique number in each “cell”:

heirs = Array.new(2, Array.new(2, 0_i32))
(0..3).each { |i|
  heirs[i//2][i%2] = i+1
}

p! heirs

This is the result I get (based on Crystal 1.3.2)

heirs # => [[3, 4], [3, 4]]

The expected outcome should have been:

heirs # => [[1, 2], [3, 4]]

Any clue on my wrong doing?

Thanks!

Update: My guess is that only one sub-array is created instead of two.
But, if so, how do I instruct crystal to create two sub-arrays?

Why can’t this library support dense array notation like numpy? The representation of matrices as a list of lists is beyond inefficient it should be illegal.

Have a look at this instead if you want to work with real matrices

PS. This works right? It creates an Array of two (distinct) arrays. You’re only calling the .new method once in the inner section so there is just one inner Array - just as you already described.

heir = [[0,0],[0,0]]
(0..3).each { |i|
  heirs[i//2][i%2] = i+1
}
1 Like

Update: My guess is that only one sub-array is created instead of two.

That’s exactly the reason. When you pass a value to Array.new(size, value), that value is used to initialize every position.

You can use the block version to use different values in every position. Try this:

heirs = Array.new(2) { Array.new(2, 0_i32) }
(0..3).each { |i|
  heirs[i//2][i % 2] = i + 1
}

p! heirs

You can also use the block version to directly initialize the array with the values you need:

heirs = Array.new(2) do |i|
  Array.new(2) do |j|
    2*i + j + 1
  end
end
p! heirs
3 Likes

Thanks!

Awesome!
The block version is concise and makes sense.
Thank you.