Working with Indexes in Lists of Lists

What Is a List of Lists?

A list of lists is exactly what it sounds like: a list where each element is itself a list. Think of it as a spreadsheet or a 2D grid. You access data using two indexes — the first for the row, the second for the column.

In Python, it looks like this:

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

This structure comes up constantly when dealing with tabular data, game boards, matrices, or any nested relationship in your code.

Accessing Elements: The Basics

The first index gives you the outer list element. The second index gives you the element inside that inner list.

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

print(matrix[0])      # [1, 2, 3]
print(matrix[0][0])   # 1
print(matrix[1][2])   # 6
print(matrix[2][1])   # 8

That's it. matrix[row][column]. Remember that indexes start at zero.

Negative Indexing Works Too

You can use negative indexes just like with regular lists:

print(matrix[-1])      # [7, 8, 9] — last row
print(matrix[-1][-1])  # 9 — last element of last row

Modifying Elements

You modify elements by targeting a specific index and assigning a new value:

matrix[1][1] = 99
print(matrix[1])  # [4, 99, 6]

The value you assign doesn't have to match the type of other elements. You can store anything in any cell.

Iterating Through a List of Lists

Using Nested For Loops

for row in matrix:
    for element in row:
        print(element, end=" ")
    print()

This prints each row on its own line. Simple and readable.

Using Range With Indexes

Sometimes you need the index positions:

for i in range(len(matrix)):
    for j in range(len(matrix[i])):
        print(f"matrix[{i}][{j}] = {matrix[i][j]}")

Use this when you're modifying elements based on their position, not just reading values.

Using Enumerate

for i, row in enumerate(matrix):
    for j, element in enumerate(row):
        print(f"Position ({i}, {j}): {element}")

Enumerate gives you the index without calling len() repeatedly. Cleaner code.

Common Operations

Adding Rows or Columns

# Add a new row
matrix.append([10, 11, 12])

# Add a new element to an existing row
matrix[0].append(4)

# Insert at specific position
matrix.insert(1, [0, 0, 0])

Removing Elements

# Remove last row
matrix.pop()

# Remove specific row
del matrix[0]

# Remove element from row
matrix[0].pop(1)

Checking If an Element Exists

[5, 6] in matrix  # True
5 in matrix[0]     # True
10 in matrix[0]    # False

The "in" operator searches only at the level you specify. It doesn't search the entire nested structure.

List of Lists vs Other Data Structures

Structure Access Speed Flexibility Best For
List of Lists Fast (index-based) High (mixed types, irregular shapes) Simple grids, irregular data
NumPy Array Fastest (contiguous memory) Low (uniform type, fixed shape) Large numerical matrices, math operations
Dictionary of Lists Fast (key-based) Medium Named columns, sparse data

For most general-purpose work, a list of lists is fine. Switch to NumPy when you're doing heavy numerical computation.

Getting Started: Practical Example

Let's build a simple tic-tac-toe board and check for a winner:

board = [
    ["X", "O", "X"],
    ["O", "X", "O"],
    ["X", " ", " "]
]

def check_winner(board):
    # Check rows
    for row in board:
        if row[0] == row[1] == row[2] != " ":
            return row[0]
    
    # Check columns
    for col in range(3):
        if board[0][col] == board[1][col] == board[2][col] != " ":
            return board[0][col]
    
    # Check diagonals
    if board[0][0] == board[1][1] == board[2][2] != " ":
        return board[0][0]
    if board[0][2] == board[1][1] == board[2][0] != " ":
        return board[0][2]
    
    return None

winner = check_winner(board)
print(f"Winner: {winner}")  # Winner: X

This shows the pattern: use nested loops to scan, access via board[row][col], and return early when you find what you need.

Common Mistakes

When to Use Something Else

A list of lists works until it doesn't. Here's when to switch:

Lists of lists are a starting point, not a destination.