Python Basics — Nested Lists

3 minute read

Nested Lists

A nested list (or list of lists) is a list where each element is itself a list. This is how Python represents 2D data structures like matrices and grids.

Creating Nested Lists

# 2D list (matrix)
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# List of mixed-length lists
jagged = [
    [1, 2],
    [3, 4, 5],
    [6]
]

Accessing Nested Elements

Use double indexing — first index selects the row, second selects the column:

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

print(matrix[0])      # [1, 2, 3]  (first row)
print(matrix[1][2])   # 6          (second row, third column)
print(matrix[-1][-1]) # 9          (last row, last column)

Modifying Nested Elements

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

matrix[0][0] = 99
print(matrix)
# [[99, 2, 3], [4, 5, 6], [7, 8, 9]]

matrix[1] = [40, 50, 60]
print(matrix)
# [[99, 2, 3], [40, 50, 60], [7, 8, 9]]

Iterating Over Nested Lists

Simple Iteration

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for row in matrix:
    for element in row:
        print(element, end=" ")
    print()
# 1 2 3
# 4 5 6
# 7 8 9

With Indices

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for i, row in enumerate(matrix):
    for j, val in enumerate(row):
        print(f"matrix[{i}][{j}] = {val}")

Flattening a Nested List

Using List Comprehension

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Using itertools.chain

from itertools import chain

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = list(chain.from_iterable(matrix))
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Creating Matrices Correctly

⚠️ Common Trap — Multiplied References

# ❌ WRONG — all rows share the same list object
matrix = [[0] * 3] * 3
matrix[0][0] = 99
print(matrix)
# [[99, 0, 0], [99, 0, 0], [99, 0, 0]]  ← all rows changed!

✅ Correct — Comprehension

# ✅ CORRECT — each row is an independent list
matrix = [[0] * 3 for _ in range(3)]
matrix[0][0] = 99
print(matrix)
# [[99, 0, 0], [0, 0, 0], [0, 0, 0]]  ← only first row changed

Deep Copy vs Shallow Copy

import copy

# Shallow copy — inner lists are still shared
original = [[1, 2], [3, 4]]
shallow = original[:]
shallow[0][0] = 99
print(original)  # [[99, 2], [3, 4]]  ← changed!

# Deep copy — fully independent
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)
deep[0][0] = 99
print(original)  # [[1, 2], [3, 4]]  ← unchanged

Practical Examples

Matrix Transpose

matrix = [
    [1, 2, 3],
    [4, 5, 6]
]

transpose = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
print(transpose)
# [[1, 4], [2, 5], [3, 6]]

Using zip():

transpose = [list(row) for row in zip(*matrix)]
print(transpose)
# [[1, 4], [2, 5], [3, 6]]

Matrix Addition

a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]

result = [
    [a[i][j] + b[i][j] for j in range(len(a[0]))]
    for i in range(len(a))
]
print(result)  # [[6, 8], [10, 12]]

Tic-Tac-Toe Board

board = [[" " for _ in range(3)] for _ in range(3)]

def print_board(b):
    for row in b:
        print(" | ".join(row))
        print("-" * 9)

board[0][0] = "X"
board[1][1] = "O"
board[2][2] = "X"
print_board(board)

Output:

X |   |  
---------
  | O |  
---------
  |   | X
---------

Summary

  • Nested lists are lists containing other lists
  • Access with double indexing: matrix[row][col]
  • Iterate with nested for loops
  • Never create matrices with [[val] * n] * m — use comprehensions
  • Shallow copies share inner objects — use copy.deepcopy() for full independence
  • Flatten with [item for row in matrix for item in row]
  • Transpose with zip(*matrix)

Next up: Lists — Practice Exercises →

Updated: