itertools: functional iteration
Chaining and Filtering
Section titled “Chaining and Filtering”Tools for combining multiple iterables or selecting elements based on conditions:
from itertools import chain, compress, takewhile, dropwhile
# chain — flatten multiple iterables into oneflat = list(chain([1, 2], [3, 4], [5, 6])) # [1, 2, 3, 4, 5, 6]flat = list(chain.from_iterable([[1, 2], [3, 4]])) # same, from a list of lists
# compress — filter by boolean maskdata = ["a", "b", "c", "d", "e"]mask = [1, 0, 1, 0, 1]print(list(compress(data, mask))) # ['a', 'c', 'e']
# takewhile — keep elements while condition is True, stop at first Falsenums = [1, 2, 3, 4, 5, 1, 2]print(list(takewhile(lambda x: x < 4, nums))) # [1, 2, 3]
# dropwhile — skip elements while condition is True, keep the restprint(list(dropwhile(lambda x: x < 4, nums))) # [4, 5, 1, 2]Note that takewhile and dropwhile operate on the first run of matching elements only — once the condition flips, they do not look back. This is why dropwhile keeps the trailing 1, 2 even though they are less than 4.
Transformation
Section titled “Transformation”Tools for applying functions across iterables:
from itertools import starmap, accumulateimport operator
# starmap — like map(), but unpacks each element as argumentspairs = [(2, 3), (4, 5), (10, 2)]
powers = list(starmap(pow, pairs)) # [8, 1024, 100]sums = list(starmap(operator.add, pairs)) # [5, 9, 12]
# accumulate — running totals (or any binary operation)sales = [100, 250, 175, 300, 225]
running_sum = list(accumulate(sales)) # [100, 350, 525, 825, 1050]running_product = list(accumulate(sales, operator.mul)) # [100, 25000, 4375000, ...]starmap is particularly useful when your data is already structured as argument tuples — it avoids the awkward map(lambda pair: f(*pair), pairs) pattern.
Grouping
Section titled “Grouping”Tools for partitioning and aligning iterables:
from itertools import groupby, zip_longest
# groupby — group consecutive elements by a key (must be sorted first!)data = [ {"name": "Alice", "dept": "Eng"}, {"name": "Bob", "dept": "Eng"}, {"name": "Carol", "dept": "HR"}, {"name": "Dave", "dept": "HR"},]
data.sort(key=lambda x: x["dept"]) # sort before groupby — critical!
for dept, members in groupby(data, key=lambda x: x["dept"]): names = [m["name"] for m in members] print(f"{dept}: {names}")# Eng: ['Alice', 'Bob']# HR: ['Carol', 'Dave']
# zip_longest — zip iterables of different lengths, fill missing valuesa = [1, 2, 3, 4, 5]b = ["a", "b", "c"]
print(list(zip_longest(a, b, fillvalue=None)))# [(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]groupby has a critical requirement — the input must be sorted by the grouping key first. Unlike SQL GROUP BY, it only groups consecutive elements, so unsorted input produces incorrect results.
Combinatorics
Section titled “Combinatorics”Tools for generating all possible arrangements of elements:
from itertools import combinations, permutations, product
items = ["A", "B", "C"]
# combinations — ordered selections, no repetitionprint(list(combinations(items, 2)))# [('A', 'B'), ('A', 'C'), ('B', 'C')]
# permutations — all orderings, no repetitionprint(list(permutations(items, 2)))# [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
# product — cartesian product (like nested for loops)print(list(product([0, 1], repeat=3)))# [(0,0,0), (0,0,1), (0,1,0), (0,1,1), (1,0,0), (1,0,1), (1,1,0), (1,1,1)]# all 3-bit binary stringsThe difference between combinations and permutations is order — ('A', 'B') and ('B', 'A') are the same combination but different permutations. product is equivalent to nested for loops and grows exponentially, so use it carefully with large inputs.
Quick Reference
Section titled “Quick Reference”| Function | Description | Lazy |
|---|---|---|
chain | Flatten multiple iterables | ✅ |
compress | Filter by boolean mask | ✅ |
takewhile | Keep while condition holds | ✅ |
dropwhile | Skip while condition holds | ✅ |
starmap | Map with argument unpacking | ✅ |
accumulate | Running totals or products | ✅ |
groupby | Group consecutive elements | ✅ |
zip_longest | Zip with fill for short iterables | ✅ |
combinations | Ordered selections, no repeat | ✅ |
permutations | All orderings, no repeat | ✅ |
product | Cartesian product | ✅ |