Skip to content
beginner Phase 1 · Python Basics

Lists & List Comprehensions

Master Python lists, slicing, methods, and list comprehension patterns.

1h 15m
0 problems
Topic Progress 0%

List Fundamentals

Creating Lists

# Empty list
empty = []
empty = list()

# List with values
numbers = [1, 2, 3, 4, 5]
fruits = ['apple', 'banana', 'cherry']
mixed = [1, 'hello', 3.14, True, None]

# List from range
numbers = list(range(10))  # [0, 1, 2, ..., 9]

# List from string
chars = list('hello')  # ['h', 'e', 'l', 'l', 'o']

Indexing and Slicing

fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']

# Indexing (0-based)
first = fruits[0]     # 'apple'
last = fruits[-1]     # 'elderberry'

# Slicing [start:stop:step]
fruits[1:3]     # ['banana', 'cherry']
fruits[:3]      # ['apple', 'banana', 'cherry']
fruits[2:]      # ['cherry', 'date', 'elderberry']
fruits[::2]     # ['apple', 'cherry', 'elderberry']
fruits[::-1]    # ['elderberry', 'date', 'cherry', 'banana', 'apple']

# Slice assignment
fruits[1:3] = ['blueberry', 'cranberry']
print(fruits)  # ['apple', 'blueberry', 'cranberry', 'date', 'elderberry']

Common List Methods

numbers = [3, 1, 4, 1, 5, 9]

# Adding elements
numbers.append(2)        # [3, 1, 4, 1, 5, 9, 2]
numbers.insert(0, 0)     # [0, 3, 1, 4, 1, 5, 9, 2]
numbers.extend([6, 7])   # [0, 3, 1, 4, 1, 5, 9, 2, 6, 7]

# Removing elements
numbers.remove(1)        # Remove first occurrence of 1
popped = numbers.pop()   # Remove and return last element
popped = numbers.pop(0)  # Remove and return element at index 0
numbers.clear()          # []

# Searching
numbers = [3, 1, 4, 1, 5, 9]
numbers.index(4)         # 2 (first occurrence)
numbers.count(1)         # 2
4 in numbers             # True

# Sorting
numbers.sort()           # In-place sort
numbers.sort(reverse=True)  # Descending
sorted_numbers = sorted(numbers)  # New sorted list

# Reversing
numbers.reverse()        # In-place reverse
reversed_numbers = numbers[::-1]  # New reversed list

List Complexity

Operation Time Space
Access by index O(1) O(1)
Search (in) O(n) O(1)
Append O(1)* O(1)
Insert at beginning O(n) O(n)
Remove O(n) O(1)
Pop from end O(1) O(1)
Pop from beginning O(n) O(1)
Sort O(n log n) O(n)

*Amortized O(1)

List Comprehensions

Basic Syntax

# [expression for item in iterable]
squares = [x ** 2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Equivalent to:
squares = []
for x in range(10):
    squares.append(x ** 2)

With Condition

# [expression for item in iterable if condition]
evens = [x for x in range(20) if x % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Filter and transform
words = ['hello', 'world', 'python', 'hi']
long_upper = [w.upper() for w in words if len(w) > 3]
# ['HELLO', 'WORLD', 'PYTHON']

Nested Comprehensions

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

# Create a matrix
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

Complex Examples

# Transpose a matrix
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transpose = [[row[i] for row in matrix] for i in range(3)]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

# Filter and transform
numbers = [1, -2, 3, -4, 5]
abs_evens = [abs(x) for x in numbers if x % 2 == 0]
# [2, 4]

# Dictionary from two lists
keys = ['name', 'age', 'city']
values = ['Alice', 30, 'NYC']
dict_from_lists = {k: v for k, v in zip(keys, values)}
# {'name': 'Alice', 'age': 30, 'city': 'NYC'}

When NOT to Use Comprehensions

# ❌ Too complex - use regular loop
result = [
    transform(x) 
    for x in items 
    if condition1(x) 
    if condition2(x)
    if condition3(x)
]

# ✅ Better: use filter() and map()
result = list(map(transform, filter(lambda x: condition1(x) and condition2(x), items)))

# ❌ Side effects in comprehension
[print(x) for x in items]  # Don't do this!

# ✅ Use a regular loop for side effects
for x in items:
    print(x)

List Copying & References

The Reference Problem

# Lists are mutable - assignment creates a reference
original = [1, 2, 3]
copy_ref = original  # Same object!

append(4) to copy_ref
copy_ref.append(4)
print(original)  # [1, 2, 3, 4] - original changed!

Shallow Copy

# Creating a shallow copy
original = [1, 2, 3]

# Method 1: slice
copy1 = original[:]

# Method 2: copy()
copy2 = original.copy()

# Method 3: list constructor
copy3 = list(original)

# Method 4: list comprehension
copy4 = [x for x in original]

# All create independent copies
copy1.append(4)
print(original)  # [1, 2, 3] - unchanged
print(copy1)     # [1, 2, 3, 4]

Deep Copy (Nested Lists)

import copy

# ⚠️ Shallow copy doesn't work for nested lists
original = [[1, 2], [3, 4]]
shallow = original.copy()

shallow[0].append(5)
print(original)  # [[1, 2, 5], [3, 4]] - nested list changed!

# ✅ Use deep copy for nested structures
deep = copy.deepcopy(original)
deep[0].append(6)
print(original)  # [[1, 2, 5], [3, 4]] - unchanged
print(deep)      # [[1, 2, 5, 6], [3, 4]]

Common Patterns

# Initialize list with default values
grid = [[0] * 3 for _ in range(3)]
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

# ⚠️ Don't use * for mutable defaults!
grid = [[0] * 3] * 3  # WRONG!
grid[0][0] = 1
print(grid)  # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] - all rows changed!

# Flatten and copy in one step
nested = [[1, 2], [3, 4], [5, 6]]
flat_copy = [num for row in nested for num in row]
# [1, 2, 3, 4, 5, 6]