Loops: Intermediate
Airbnb's pricing engine uses zip to pair availability calendars with pricing calendars for millions of listings simultaneously, iterating both sequences in lockstep to compute dynamic rates without a single index variable. When engineers process two related data streams at the same time, zip turns a nested loop into a single clean iteration that is both faster and easier to read. The intermediate loop patterns in this lesson, including enumerate, zip, and break/continue, are the toolkit that separates readable production code from amateur scripts.
enumerate() for Index
Track position and value together
The enumerate() function adds a counter to an iterable. It returns pairs of (index, value) on each iteration, giving you access to both the position and the item without manually managing an index variable.
Basic enumerate Usage
enumerate(iterable) returns an enumerate object that yields (index, item) tuples. You typically unpack these in the for statement:
The index, fruit syntax unpacks the tuple returned by enumerate. The first value is the index, the second is the item from the list.
Starting at Any Index
By default, enumerate starts counting at 0. Use the start parameter to begin at a different number:
enumerate() Patterns
enumerate is essential when you need to modify a list in place or when position matters:
Try changing the start parameter to see how enumerate adjusts the counter. Each option produces a different numbering scheme:
> The enumerate function pairs each item with an index. Pick a start value to see how the numbering changes.
colors = ["red", "green", "blue"] for i, c in enumerate(colors, start=): print(i, c)
enumerate() for Strings
enumerate() for Progress
Here are the most common scenarios where enumerate() saves you from manual index tracking:
zip() Parallel Iteration
Iterate multiple lists in lockstep
The zip() function combines multiple iterables element-by-element. On each iteration, it yields a tuple containing one item from each input sequence. This lets you iterate over related data in parallel.
Basic zip Usage
zip(iterable1, iterable2, ...) pairs up items from each iterable by position:
zip() with Unequal Lengths
- Need just values: plain
forloop over the sequence. - Need index and value: enumerate() with tuple unpacking.
- Need values from two or more lists in lockstep: zip().
- Need index plus multiple lists: enumerate(zip(a, b)).
zip() with Multiple Lists
Dicts from zip()
Combining zip and enumerate
Transposing with zip
A clever use of zip with the * unpacking operator transposes rows and columns in a matrix:
> Pair names with their scores so each element is a tuple. Pick the built-in that combines two sequences element-by-element, and the one that counts the resulting pairs.
names = ["Alice", "Bob"] scores = [85, 92] pairs = list((names, scores)) print(pairs[0]) print((pairs))
zip() is lazy: it does not build a list in memory until you ask for it. Wrap it in list() to materialize all pairs, or iterate directly in a for loop to process one pair at a time.
enumerate() and zip() cover the two most common iteration patterns: working with a single sequence with positional context, or working with multiple parallel sequences together.
When zipping sequences of different lengths, zip() stops at the shortest one. Use itertools.zip_longest() if you need to process all elements and fill missing values with a default.
Iterating Dict Items
Loop through dict keys, values, or both
Iterating Over Keys
Iterating Over Values
Use .values() to iterate over just the values:
Iterating Key-Value Pairs
Use .items() to get both key and value together. This is the most commonly used pattern:
- for key in dict: - iterate keys
- for val in dict.values(): - iterate values
- for k, v in dict.items(): - key-value pairs
- Keys only: checking membership
- Values only: aggregations
- Items: most common, need both
Filtering Dict Entries
Iterating Nested Dicts
Building Dicts from Loops
collections.defaultdict and dict.setdefault() methods can simplify this, which you'll learn in more advanced lessons.- Use .items() when you need both key and value
- Use dict comprehension for filtering
- Iterate over list(dict.keys()) to modify
- Use descriptive names for k, v
- Add or delete keys while iterating directly
- Use dict[key] inside a for-key loop when .items() works
- Assume insertion order in Python < 3.7
- Modify values through a values() view
> Sum the numeric values and collect the key names from a dictionary. Pick the accessor that returns just the numbers, and the one that returns just the names.
data = {"x": 10, "y": 20, "z": 30} total = sum(data.()) names = list(data.()) print(total) print(names[0])
Choosing the right dictionary view method keeps your intent clear. Use .keys() when only the labels matter, .values() when only the data matters, and .items() when you need both together.
Nested Loops
Process grids and generate combinations
Basic Nested Loop
Working with 2D Data
Generating Combinations
Triangle and Pyramid
> This nested loop should print a multiplication table, but the formula is wrong. Remove the extra tile to fix it.
LogicError: printing i*i*j instead of i*j. The table values are wrong.
Searching in 2D Structures
Loop else Clauses
Detect when a search finds nothing
Python has a unique feature: you can attach an else clause to loops. The else block executes when the loop completes normally (without hitting a break). If break terminates the loop, the else block is skipped.
The for-else Pattern
Think of for-else as "for...else if no break". In the first loop, no even number exists, so the loop completes normally and else runs. In the second loop, break executes, so else is skipped.
The while-else Pattern
Practical Use Cases
> You are a data engineer at Salesforce processing multi-dimensional user activity logs, pairing each user with their corresponding event sequence to calculate weekly engagement scores across product lines.
else clause signals cleanly when a full user scan completes without finding an expected anchor event to score against.else runs only if loop completes without break; great for searchesPowerful iteration techniques
- Category
- Python
- Difficulty
- intermediate
- Duration
- 36 minutes
- Challenges
- 0 hands-on challenges
Topics covered: enumerate() for Index, zip() Parallel Iteration, Iterating Dict Items, Nested Loops, Loop else Clauses
Lesson Sections
- enumerate() for Index (concepts: pyEnumerate)
Basic enumerate Usage Starting at Any Index enumerate() Patterns enumerate() for Strings Enumerate works with any iterable, including strings. This is useful for finding character positions or processing text with position awareness: enumerate() for Progress When processing large datasets or files, enumerate helps display progress to users:
- zip() Parallel Iteration (concepts: pyZip)
Basic zip Usage On the first iteration, you get ("Alice", 25). On the second, ("Bob", 30). The items are paired by their position in each list. zip() with Unequal Lengths When sequences have different lengths, zip stops at the shortest one: Knowing when to reach for enumerate versus zip versus plain iteration saves you from writing unnecessary boilerplate. Here is a concise guide. zip() with Multiple Lists You can zip together any number of sequences: Dicts from zip() A common pattern is using z
- Iterating Dict Items (concepts: pyDictIterate)
Dictionaries provide several methods for iteration: you can loop over just keys, just values, or key-value pairs together. Each approach is useful in different situations. Iterating Over Keys By default, iterating over a dictionary yields its keys: Iterating Over Values Iterating Key-Value Pairs Filtering Dict Entries Common patterns when working with dictionary iteration: Iterating Nested Dicts Real-world data often involves dictionaries containing other dictionaries. You can use nested loops t
- Nested Loops (concepts: pyNestedLoops)
A nested loop is a loop inside another loop. The inner loop runs completely for each iteration of the outer loop. This pattern is essential for working with multi-dimensional data structures and generating combinations. Basic Nested Loop The inner loop completes all its iterations before the outer loop moves to the next item: The outer loop runs 3 times. For each outer iteration, the inner loop runs 2 times. Total iterations: 3 x 2 = 6. Working with 2D Data Nested loops are natural for processin
- Loop else Clauses (concepts: pyLoopElse)
The for-else Pattern The else block runs only if the loop completed without breaking: The while-else Pattern The else clause works identically with while loops: Practical Use Cases Loop-else is ideal for search patterns where you need to know if the search succeeded: The prime number check is a classic example. The loop searches for a divisor. If it finds one, it breaks. If the loop finishes without breaking, the else clause confirms the number is prime: Mastering loop patterns helps you write m