{ }codelper

Learn › Python

Going further · 18

2D lists (grids)

Grids of rows and columns: reading them, row and column sums, and neighbours inside the bounds.

A 2D list is a list of lists.
grid[i][j] means column j of row i.
The example below reads a grid, finds the row and column sums, and prints the sum of each cell's neighbours.

r, c = map(int, input().split())grid = [list(map(int, input().split())) for _ in range(r)]print(*[sum(row) for row in grid])print(*[sum(grid[i][j] for i in range(r)) for j in range(c)])moves = [(-1, 0), (1, 0), (0, -1), (0, 1)]near = [[0] * c for _ in range(r)]for i in range(r):    for j in range(c):        for di, dj in moves:            ni, nj = i + di, j + dj            if 0 <= ni < r and 0 <= nj < c:                near[i][j] += grid[ni][nj]for row in near:    print(*row)
stdin
3 4
1 2 3 4
5 6 7 8
9 10 11 12
stdout
10 26 42
15 18 21 24
7 10 13 11
16 24 28 23
15 26 29 19

Key points

  • To visit every cell, put a loop over columns inside a loop over rows (a nested loop).
  • Row sums add up the cells of each row; column sums walk down each column.
    You can also add into rowSums[i] and colSums[j] together in one pass.
  • For neighbours (up, down, left, right), keep the directions in lists such as di = [-1, 1, 0, 0] and dj = [0, 0, -1, 1] and loop over them.
    The code gets short.
  • On the edge a neighbour falls outside.
    Always check 0 <= ni < r and 0 <= nj < c before reading, including the negative side.
  • Each row must be created separately.
    If the same row goes in several times, changing one cell changes every row.

How each language writes it

Python[[0] * c for _ in range(r)].
grid[-1] is not an error but the last row
JavaScriptArray.from({ length: r }, () => new Array(c).fill(0)).
A cell outside is undefined; reading a cell of a row outside throws TypeError
TypeScriptSame as JavaScript.
The type is number[][]
Javanew int[r][c] — filled with zeros.
Out of range: ArrayIndexOutOfBoundsException
C#Two kinds: the rectangular array int[r, c] (read with grid[i, j]) and the jagged array of arrays int[r][].
Out of range: IndexOutOfRangeException
C++vector<vector<int>>(r, vector<int>(c)).
[] does not check the range
CFix the size in advance, like int grid[100][100], and use only the top-left part.
Reading out of range says nothing
CraykonBuild it row by row with grid.Add(Console.ReadNumbers()), and make a row of c zeros with NewList(c, 0).
Out of range stops with an error saying the list only has items 0 to 3

Common mistakes

Reading the top row's upper neighbour without a checkPython

grid = [[1, 2], [3, 4]]
i, j = 0, 0
print(grid[i - 1][j])

→ 3 — grid[-1] is the last row, so it quietly reads from the bottom row

Check the negative side too: 0 <= ni < r.

Skipping the range checkJavaScript · TypeScript · C · C++

const grid = [[1, 2], [3, 4]];
console.log(1 + grid[0][2]);
console.log(grid[2][0]);

→ Prints NaN, then the next line stops with a TypeError. C and C++ silently read the next row or unrelated memory

Check 0 <= ni && ni < r && 0 <= nj && nj < c before reading.
Java, C# and Craykon stop with an index error.

How languages differ
Python [[0] * c] * r makes r references to one and the same row: after g = [[0] * 3] * 2; g[0][0] = 5 you get [[5, 0, 0], [5, 0, 0]].
JavaScript new Array(r).fill(new Array(c).fill(0)) does the same, so always create each row separately.

Practice