product, permutations and combinations

itertools · Practical · 10 min

Grid searches, test matrices, brute-force search and probability counting all enumerate combinations.

Four combinatoric iterators:

  • product(a, b) every pair (x, y) with x from a and y from b, like nested for-loops (the rightmost varies fastest). product(range(2), repeat=3) gives all 3-bit tuples.
  • permutations(items, r) every ordering of r items without repetition; r defaults to all.
  • combinations(items, r) every subset of size r, order ignored, in lexicographic order of positions.
  • combinations_with_replacement(items, r) subsets where items may repeat.

They treat input elements by position, not value: permutations("aab") yields duplicates. Deduplicate with a set if needed.

Sizes grow explosively: permutations(range(10)) yields 3,628,800 tuples; product(range(10), repeat=8) yields 100 million. Since they're lazy, iterating is fine if you stop early or filter; list() of them may exhaust memory. Compute counts without generating, using math.perm, math.comb and math.prod.

product reads all its inputs into memory first (it needs to loop over them repeatedly), so pass finite iterables.

Typical uses: hyperparameter grids (product(lrs, batch_sizes)), test parameter matrices, pairs of items to compare (combinations(items, 2)), and small brute-force searches.

Example

import math
from itertools import combinations, combinations_with_replacement, permutations, product

print(list(product("ab", [1, 2])))     # [('a', 1), ('a', 2), ('b', 1), ('b', 2)]
print(len(list(product([0, 1], repeat=3))))     # 8
print(list(permutations("abc", 2))[:3])          # [('a', 'b'), ('a', 'c'), ('b', 'a')]
print(list(combinations("abcd", 2)))
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
print(list(combinations_with_replacement("ab", 2)))  # [('a', 'a'), ('a', 'b'), ('b', 'b')]
print(math.comb(52, 5), math.perm(10))         # 2598960 3628800

grid = {"lr": [0.1, 0.01], "depth": [3, 5]}
configs = [dict(zip(grid, values)) for values in product(*grid.values())]
print(configs[1])                              # {'lr': 0.1, 'depth': 5}
print(len(set(permutations("aab"))))           # 3

Remember

  • product = nested loops; permutations = orderings; combinations = subsets
  • Elements are distinguished by position, so duplicate values give duplicate results
  • Counts explode; use math.comb/math.perm to size them first

Watch out for

  • Calling list(permutations(...)) on more than about 10 items and running out of memory.

Check yourself

  1. How many tuples does combinations('abcde', 3) yield?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/itertools.html#itertools.combinations