Skip to main content

Iterating a two-dimensional array

Iterating a two-dimensional array (a matrix) is one of the basic but genuinely important operations. Because it is an array of arrays, you walk it with nested loops: the outer one over rows, the inner one over columns. Which form you pick depends on whether you need the indexes and whether you have to be able to stop the loop early.

Theory

TL;DR

  • A two-dimensional array is traversed with nested loops: outer over rows, inner over the elements of a row.
  • A classic for gives full control and access to the i and j indexes.
  • Two nested for...of loops are the most readable modern option.
  • forEach() hands you the indexes as a second argument, but it cannot be stopped with break.
  • flat() turns the matrix into a one-dimensional array when indexes do not matter.
  • reduce() fits aggregation, for example summing every element.

Quick example

Every example below works on this matrix:

javascript
const matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; for (const row of matrix) { for (const value of row) { console.log(value); // 1, 2, 3, 4, ... 9 } }

The classic way with for

javascript
for (let i = 0; i < matrix.length; i++) { for (let j = 0; j < matrix[i].length; j++) { console.log(`matrix[${i}][${j}] = ${matrix[i][j]}`); } }
  • i is the row index,
  • j is the column index,
  • matrix[i][j] is the element in row i and column j.

Output:

javascript
matrix[0][0] = 1 matrix[0][1] = 2 // ... matrix[2][2] = 9

This form gives full control: you can go backwards, skip elements, and leave with break or continue.

for...of and forEach()

for...of iterates over values, so the code is shorter:

javascript
for (const row of matrix) { for (const value of row) { console.log(value); } }

The outer for...of goes over rows, the inner one over the elements inside a row. This is the most readable and most modern way to iterate, and you can still stop it with break.

forEach() does the same thing in a functional style and gives you the indexes for free:

javascript
matrix.forEach((row, i) => { row.forEach((value, j) => { console.log(`matrix[${i}][${j}] = ${value}`); }); });

It needs no manual counter and reads well in functional code, but you cannot break out of it with break or return: a return only ends the current callback call.

flat() when indexes do not matter

If you only need to visit every element in a row, you can flatten the matrix:

javascript
matrix.flat().forEach(value => console.log(value));

flat() turns a two-dimensional array into an ordinary one-dimensional one:

javascript
matrix.flat(); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

The downside is that you lose the row and column information, and you allocate a new array in memory.

reduce() for calculations

If you need, for example, the sum of every element:

javascript
const sum = matrix.reduce( (acc, row) => acc + row.reduce((a, b) => a + b, 0), 0 ); console.log(sum); // 45

The inner reduce sums one row, the outer one adds the rows together.

Comparing the options

WayWhat it doesCan the loop be stopped
forFull control, indexesYes
for...ofSimple and readable traversalYes
forEach()Functional styleNo
flat() plus forEach()Visits all values as a flat arrayNo
reduce()Aggregation, a sum for exampleYes, logically

Bottom line: for walking a two-dimensional array,

javascript
for (const row of matrix) { for (const value of row) { console.log(value); } }

is the modern, readable and safe way to do it.

Common mistakes

  • break inside forEach(). That is a syntax error, and return only exits a single callback call. When you need an early exit, use for or for...of.
  • One loop instead of two. matrix.forEach(row => console.log(row)) prints arrays, not values; the values need a second level of iteration.
  • Bounding by matrix[0].length. On jagged arrays with rows of different lengths this either skips elements or yields undefined; use matrix[i].length.
  • for...in instead of for...of. for...in walks keys, that is the string indexes "0", "1", and it also picks up any own enumerable properties of the array.
  • flat() where coordinates are needed. After flattening there is no way to tell which row a value came from.
  • Changing the array length while iterating. A push or splice inside the loop shifts the indexes and leads to skipped or repeated elements.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.