A plain
The trick is beautifully simple: a two-dimensional array is just an array whose elements are themselves arrays. The outer array holds the rows; each inner array is one row of the grid. Here is a tiny 3 × 3 noughts-and-crosses board, written as three rows stacked one under another:
Read it top to bottom and it looks exactly like the game. board is one array with
three elements — and each of those elements is itself an array of three symbols. An array of
arrays: that's all a 2-D array is.
grid[row][col]A one-dimensional array needs one index to pin down an element. A grid needs two: one to choose the row, then one to choose the column within that row. You write them as two sets of square brackets, row first:
Just like ordinary arrays, both indices start at zero. The top-left cell is
grid[0][0]; move one column right and it's grid[0][1]; move down one row
instead and it's grid[1][0]. The diagram below shows every cell of a 3 × 4
grid labelled with its [row][col] address — trace a few with your finger:
Think of it as a two-step lookup. board[2] hands you back a whole row — the
array ["X", " ", "O"]. Then a second index picks one element out of that row:
board[2][0] is "X". The first bracket chooses the row; the second reaches
into it.
Once you know the address, reading a cell is nothing new — and you can change one just by assigning to it. Here we make a board, read a couple of cells, then place a fresh move. Press Run:
Notice the type: string[][] reads as "an array of arrays of strings" — the double
[] is the giveaway that you're looking at a grid. A grid of numbers would be
number[][].
The .length property still works, and it answers two different questions depending on
where you use it. board.length is the number of rows (the size of the
outer array); board[0].length is the number of columns (the size of
one row). Together they tell you the shape of the whole grid.
To visit every element of a one-dimensional array you used one loop. A grid has two dimensions, so you need two loops, one inside the other — a nested loop. The outer loop walks down the rows; for each row, the inner loop walks across the columns. Together they touch every cell exactly once, like reading a book: along each line, then down to the next.
Read the two conditions carefully. The outer r runs from board.length (the row count); the inner c runs from
board[r].length (that row's column count). Inside,
board[r][c] is the current cell. Nine cells, printed in order: row 0 left-to-right,
then row 1, then row 2.
The loop above printed one cell per line — fine for the computer, ugly for us. Usually you want the inner loop to build up one line of text per row, and only print at the end of each row. That draws the grid as a grid:
The shape of the code mirrors the shape of the job: the outer loop is "for each row", and building a
fresh line at its top (then printing at its bottom) is what keeps the rows on separate
lines. Move that console.log(line) inside the inner loop by mistake and the whole thing
collapses.
Grids often hold numbers — a table of monthly rainfall, marks in several subjects, sales per shop. To total everything, use the same nested loop but keep a running total (an accumulator), adding each cell as you pass it. Here are three pupils' marks in four subjects:
You can total just one row (a single pupil) by looping the columns of that row alone, or one column (a single subject across all pupils) by fixing the column and looping the rows. Choosing which index to hold still and which to run is how you slice a grid any way you like:
A digital image is really a 2-D array of pixels. Each cell holds the colour of
one tiny dot, addressed by its row and column — image[y][x]. A modest phone photo is
a grid roughly
Sometimes you don't have the values yet — you want a blank board to fill during a game, or a grid of
zeros to count into. You can write out every row by hand for a small grid, or, for a bigger one,
build it with loops. This makes a
The single biggest 2-D-array mistake is getting the two indices the wrong way round.
The order is fixed: row first, then column — grid[row][col]. Swap
them and you don't get an error message; you silently read the wrong cell, or fall off the
edge of the grid. In a grid with grid[4][1] asks for row 4 — which doesn't exist — while the cell you
meant, grid[1][4], was perfectly valid:
And remember both indices are zero-based, exactly like a one-dimensional array. A
grid of grid.length - 1, not grid.length), and a row of
r and c (or row and
col) so the order is obvious, and say the address out loud — "row two, column zero" —
before you type it.