2

I have studied C++, Java and I am learning Ruby now.
but It's hard to adapt to iteration in ruby for me yet.

n = 4
arys = Array.new(3, Array.new(n+1, 0))

for i in 1..2
    for j in 1..n
        arys[i][j] = (i-1)*n+j
    end
end

p arys

output of above code is as below

[[0, 5, 6, 7, 8], [0, 5, 6, 7, 8], [0, 5, 6, 7, 8]]

I thought it is like code as below in C

for(int i = 1; i<=2; i++)
   for(int j = 1; j<=n; j++)
       arys[i][j] = (i-1)*n+j

therefore, I expected the output will be like
[[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 5, 6, 7, 8]]

what make the difference between above two codes?

2 Answers 2

6

In the very initialization line for arys you actually have created one inner array, referenced three times by arys outermost array:

arys.map &:__id__
#⇒ [
#  [0] 28193580,
#  [1] 28193580,
#  [2] 28193580
# ]

__id__ above states for unique object identifier.

To achieve the behaviour you expected, one should produce three different arrays, e.g.:

ary = Array.new(5, 0)
arys = 3.times.map { ary.dup }

Note dup above, that clones the object. Now we have three different objects (arrays)

arys.map &:__id__
#⇒ [
#  [0] 34739980,
#  [1] 34739920,
#  [2] 34739860
# ]

and your code will work as expected.

2
  • 1
    Oh.. I didn't know that This was just duplicating single reference! Thanks!
    – astrohsy
    Commented Jan 26, 2016 at 12:01
  • 1
    @Stefan Indeed, I just wanted to make things as clear as possible, I corrected an answer to make dup not redundant. Commented Jan 26, 2016 at 13:12
1

You can also take advantage of Array#new with a block, and use below code:

arys = Array.new(3) {Array.new(n+1, 0)}

Here, we pass a block to outer array constructor so that we can create an array of size n+1 and default element values of 0 for sub-arrays (as needed in your problem statement).


Also, if you wish to use something other than for loop, here is one variant that will have same output:

(1...arys.size).each do |i|
    (1..n).each do |j|
        arys[i][j] = (i-1)*n + j
    end
end

Note use of ... in 1...arys.size to use exclusive range. 1...10 is equivalent of to 1..9, in other words (1..9).to_a == (1...10).to_a will be true

4
  • 1
    You can omit |i| since the argument it is not used.
    – Stefan
    Commented Jan 26, 2016 at 12:26
  • @Stefan danke sehr - I always miss finer details.
    – Wand Maker
    Commented Jan 26, 2016 at 12:31
  • 1
    Gern geschehen ;-) BTW, "whenever an index is accessed for first time" is the way Hash.new works. Array.new creates its elements immediately.
    – Stefan
    Commented Jan 26, 2016 at 13:02
  • @Stefan Thanks again. I have learned a lot with feedback like this and looking at answers of others.
    – Wand Maker
    Commented Jan 26, 2016 at 13:08

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.