davidhu2000 davidhu2000 - 1 year ago 126
Ruby Question

Ruby 2D array assignment

So I have a tic-tac-toe

class. See below:

class Board
attr_accessor :grid

def initialize(grid = Array.new(3, Array.new(3, nil)))
@grid = grid

def place_mark(position, symbol)
@grid[position[0]][position[1]] = symbol

Whenever I call the
method, and tried to assign a symbol to an element in the 2D array, the entire column gets assigned.

board = Board.new
board.place_mark([0,0], :x)

Would result in

[[:X, nil, nil],
[:X, nil, nil],
[:X, nil, nil]]

Where the desired result is

[[:X , nil, nil],
[nil, nil, nil],
[nil, nil, nil]]

I found a solution to my problem, in the
method, I just need to assign the default value of grid like this:

def initialize(grid = [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]])
@grid = grid

Then the
method works just fine.

So my question is how are the two different array declarations different that would make them behave this way?

Answer Source

The issue is that Array.new(3, Array.new(3, nil)) gives you an array with the same array in it three times.

It's like doing this:

x = Array.new(3, nil)
grid = Array.new(3, x)

So you have an array containing x three times. You really want three separate arrays that can each have their own values.

Per http://ruby-doc.org/core-2.3.1/Array.html:

Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false.

To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays:

Array.new(4) { Hash.new } #=> [{}, {}, {}, {}]

This is also a quick way to build up multi-dimensional arrays:

empty_table = Array.new(3) { Array.new(3) }
#=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

That last example is exactly what you're looking for.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download