Grid searches, test matrices, brute-force search and probability counting all enumerate combinations.
Four combinatoric iterators:
product(a, b)every pair(x, y)withxfromaandyfromb, like nested for-loops (the rightmost varies fastest).product(range(2), repeat=3)gives all 3-bit tuples.permutations(items, r)every ordering ofritems without repetition;rdefaults to all.combinations(items, r)every subset of sizer, 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")))) # 3Remember
- product = nested loops; permutations = orderings; combinations = subsets
- Elements are distinguished by position, so duplicate values give duplicate results
- Counts explode; use
math.comb/math.permto size them first
Watch out for
- Calling
list(permutations(...))on more than about 10 items and running out of memory.