Reasoning Into CodeArunank Divya Sharan · Python edition← Arunank’s portfolio
Module 13 · Matrix Traversal and Simulation

121. Row and Column Totals

Foundation · Download this solution · All solutions and shared helpers

Problem

For a rectangular integer matrix, return (row_totals,column_totals). Each row total includes all its columns and each column total includes all its rows. Empty input returns two empty lists. A matrix with rows but zero columns has zero for each row total.

Examples

Example 1

matrix_totals([[1,2,3],[4,5,6]])
=> ([6, 15], [5, 7, 9])

A nonsquare matrix distinguishes the two dimensions.

Example 2

matrix_totals([])
=> ([], [])

Neither dimension has entries.

Example 3

matrix_totals([[],[]])
=> ([0, 0], [])

Empty rows still have zero row totals.

Reveal the worked solution and reasoning

Why this mechanism works

Each cell contributes to exactly two independent summaries, one named by its row and one by its column. A single nested traversal can update both. The row and column indices are coordinates, while their corresponding accumulators have different output dimensions.

State and boundaries

row_totals has one accumulator per row; column_totals has one per column. Each includes exactly the cells consumed so far in that row or column.

Protocol

  1. Allocate zero accumulators for both dimensions.
  2. Visit every (r,c) cell.
  3. Add its value to row_totals[r] and column_totals[c].
  4. Return both lists.

Visualization

1 2 3 -> row total 6
4 5 6 -> row total 15
| | |
5 7 9 -> column totals

Python implementation

def matrix_totals(matrix):
    rows = len(matrix)
    cols = len(matrix[0]) if rows else 0
    row_totals, column_totals = [0] * rows, [0] * cols
    for r in range(rows):
        for c in range(cols):
            row_totals[r] += matrix[r][c]
            column_totals[c] += matrix[r][c]
    return row_totals, column_totals

Worked execution

Recorded state changes after statements; L numbers refer to the solution file. Long traces are explicitly condensed.

matrix_totals([[1,2,3],[4,5,6]])

L2 matrix_totals: rows = len(matrix)
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2

L3 matrix_totals: cols = len(matrix[0]) if rows else 0
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3

L4 matrix_totals: row_totals, column_totals = [0] * rows, [0] * cols
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[0, 0]; column_totals=[0, 0, 0]

L5 matrix_totals: for r in range(rows):
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[0, 0]; column_totals=[0, 0, 0]; r=0

L6 matrix_totals: for c in range(cols):
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[0, 0]; column_totals=[0, 0, 0]; r=0; c=0

L7 matrix_totals: row_totals[r] += matrix[r][c]
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[1, 0]; column_totals=[0, 0, 0]; r=0; c=0

L8 matrix_totals: column_totals[c] += matrix[r][c]
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[1, 0]; column_totals=[1, 0, 0]; r=0; c=0

L6 matrix_totals: for c in range(cols):
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[1, 0]; column_totals=[1, 0, 0]; r=0; c=1

... 11 intermediate state changes omitted ...

L8 matrix_totals: column_totals[c] += matrix[r][c]
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[6, 9]; column_totals=[5, 7, 3]; r=1; c=1

L6 matrix_totals: for c in range(cols):
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[6, 9]; column_totals=[5, 7, 3]; r=1; c=2

L7 matrix_totals: row_totals[r] += matrix[r][c]
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[6, 15]; column_totals=[5, 7, 3]; r=1; c=2

L8 matrix_totals: column_totals[c] += matrix[r][c]
matrix=[[1, 2, 3], [4, 5, 6]]; rows=2; cols=3; row_totals=[6, 15]; column_totals=[5, 7, 9]; r=1; c=2

Result: ([6, 15], [5, 7, 9]). A nonsquare matrix distinguishes the two dimensions.

matrix_totals([])

L2 matrix_totals: rows = len(matrix)
matrix=[]; rows=0

L3 matrix_totals: cols = len(matrix[0]) if rows else 0
matrix=[]; rows=0; cols=0

L4 matrix_totals: row_totals, column_totals = [0] * rows, [0] * cols
matrix=[]; rows=0; cols=0; row_totals=[]; column_totals=[]

Result: ([], []). Neither dimension has entries.

Why the solution is correct

Each cell is visited once and added once to each relevant accumulator. No other row or column receives that contribution. Therefore each final accumulator contains precisely the sum of its own cells.

Time and space

O(rows*cols) time and O(rows+cols) returned storage.

Common mistakes

Allocating column totals using the row count fails for nonsquare matrices. Swapping r and c can pass square examples while remaining wrong.

Reasoning card

State: row_totals has one accumulator per row; column_totals has one per column. Each includes exactly the cells consumed so far in that row or column.

Invariant: Each cell contributes once to its row and column accumulator.

Decision to rehearse: Reset row-local state; retain column-global state.

Finish: Return both lists

Transfer exercise

Also compute main and anti-diagonal totals for a square matrix without another traversal.