Mathew K Analytics

Lesson 5 · Python standard library deep dive

Python itertools Explained: Iterators, Combinations & More | Standard Library #5

Video five of the twenty-five-part series: itertools, fast, memory-efficient building blocks for looping. Infinite iterators, combinatorics, and tools for…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Python Standard Library Deep-Dive, Video 5: itertools#

  • Video five of the twenty-five-part series: itertools, fast, memory-efficient building blocks for looping.
  • Infinite iterators, combinatorics, and tools for chaining, filtering, and grouping.
  • Let's get into it.

Part 1: What itertools Offers#

import itertools
result = itertools.count(1)
print(type(result))
first_five = [next(result) for _ in range(5)]
print(first_five)
<class 'itertools.count'>
[1, 2, 3, 4, 5]

Part 2: Infinite Iterators: count(), cycle(), repeat()#

evens = itertools.count(0, 2)
print(list(itertools.islice(evens, 5)))
colors = itertools.cycle(['red', 'green', 'blue'])
print(list(itertools.islice(colors, 7)))
padded = itertools.repeat('x', 4)
print(list(padded))
infinite_repeat = itertools.repeat('y')
print(list(itertools.islice(infinite_repeat, 3)))
[0, 2, 4, 6, 8]
['red', 'green', 'blue', 'red', 'green', 'blue', 'red']
['x', 'x', 'x', 'x']
['y', 'y', 'y']

Part 3: Combining Iterators: chain() and zip_longest()#

a = [1, 2, 3]
b = ['x', 'y']
c = (True, False)
combined = list(itertools.chain(a, b, c))
print(combined)
print(list(zip(a, b)))
print(list(itertools.zip_longest(a, b, fillvalue='-')))
[1, 2, 3, 'x', 'y', True, False]
[(1, 'x'), (2, 'y')]
[(1, 'x'), (2, 'y'), (3, '-')]

Part 4: Filtering: takewhile(), dropwhile(), filterfalse(), compress()#

nums = [1, 3, 5, 8, 9, 11, 2]
print(list(itertools.takewhile(lambda n: n % 2 != 0, nums)))
print(list(itertools.dropwhile(lambda n: n % 2 != 0, nums)))
print(list(itertools.filterfalse(lambda n: n % 2 == 0, nums)))
letters = ['a', 'b', 'c', 'd']
selectors = [1, 0, 1, 0]
print(list(itertools.compress(letters, selectors)))
[1, 3, 5]
[8, 9, 11, 2]
[1, 3, 5, 9, 11]
['a', 'c']

Part 5: Combinatorics: product(), permutations(), combinations(), combinations_with_replacement()#

sizes = ['S', 'M', 'L']
colors = ['red', 'blue']
print(list(itertools.product(sizes, colors)))
print(len(list(itertools.product(sizes, colors))))
dice = list(itertools.product(range(1, 7), repeat=2))
print(len(dice))
[('S', 'red'), ('S', 'blue'), ('M', 'red'), ('M', 'blue'), ('L', 'red'), ('L', 'blue')]
6
36
letters = ['A', 'B', 'C']
print(list(itertools.permutations(letters)))
print(list(itertools.permutations(letters, 2)))
print(list(itertools.combinations(letters, 2)))
print(list(itertools.combinations_with_replacement(letters, 2)))
[('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]
[('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]
[('A', 'B'), ('A', 'C'), ('B', 'C')]
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')]

Part 6: groupby()#

data = [1, 1, 2, 2, 2, 3, 1, 1]
for key, group in itertools.groupby(data):
    print(key, list(group))
1 [1, 1]
2 [2, 2, 2]
3 [3]
1 [1, 1]
words = ['apple', 'banana', 'avocado', 'blueberry', 'cherry', 'apricot']
sorted_words = sorted(words, key=lambda w: w[0])
for first_letter, group in itertools.groupby(sorted_words, key=lambda w: w[0]):
    print(first_letter, list(group))
a ['apple', 'avocado', 'apricot']
b ['banana', 'blueberry']
c ['cherry']

Part 7: accumulate()#

nums = [1, 2, 3, 4, 5]
print(list(itertools.accumulate(nums)))
import operator
print(list(itertools.accumulate(nums, operator.mul)))
print(list(itertools.accumulate(nums, max)))
[1, 3, 6, 10, 15]
[1, 2, 6, 24, 120]
[1, 2, 3, 4, 5]

Part 8: starmap()#

pairs = [(2, 3), (4, 5), (6, 2)]
print(list(itertools.starmap(pow, pairs)))
print(list(map(lambda p: pow(p[0], p[1]), pairs)))
[8, 1024, 36]
[8, 1024, 36]

Part 9: Common Patterns#

def chunked(iterable, size):
    it = iter(iterable)
    while True:
        chunk = list(itertools.islice(it, size))
        if not chunk:
            return
        yield chunk
data = list(range(10))
for batch in chunked(data, 3):
    print(batch)
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9]

Wrap-Up: What You Learned#

  • Every itertools function returns a lazy iterator, computed one value at a time.
  • Infinite iterators: count, cycle, repeat, always paired with islice or another limiter.
  • Combining: chain and zip_longest.
  • Filtering: takewhile, dropwhile, filterfalse, compress.
  • Combinatorics: product, permutations, combinations, combinations_with_replacement.
  • groupby for clustering consecutive runs, almost always paired with a prior sort.
  • accumulate for running totals or any running binary operation, and starmap for pre-packed argument tuples.
  • A real chunking pattern built entirely from islice.
  • That wraps up itertools. Next up: functools, for higher-order function tools.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.