The itertools module provides memory-efficient combinatoric iterators. Generate all possible arrangements without materializing them in memory.
Permutations
All possible orderings:
from itertools import permutations
# All permutations of a sequence
items = ['a', 'b', 'c']
for p in permutations(items):
print(p)
# ('a', 'b', 'c')
# ('a', 'c', 'b')
# ('b', 'a', 'c')
# ('b', 'c', 'a')
# ('c', 'a', 'b')
# ('c', 'b', 'a')
# Permutations of length r
for p in permutations(items, r=2):
print(p)
# ('a', 'b')
# ('a', 'c')
# ('b', 'a')
# ('b', 'c')
# ('c', 'a')
# ('c', 'b')Combinations
Subsets without regard to order:
from itertools import combinations
items = ['a', 'b', 'c', 'd']
# All 2-element combinations
for c in combinations(items, 2):
print(c)
# ('a', 'b')
# ('a', 'c')
# ('a', 'd')
# ('b', 'c')
# ('b', 'd')
# ('c', 'd')
# All 3-element combinations
list(combinations(items, 3))
# [('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd')]Combinations with Replacement
Allow repeated elements:
from itertools import combinations_with_replacement
items = ['a', 'b', 'c']
for c in combinations_with_replacement(items, 2):
print(c)
# ('a', 'a')
# ('a', 'b')
# ('a', 'c')
# ('b', 'b')
# ('b', 'c')
# ('c', 'c')Cartesian Product
All possible pairs from multiple iterables:
from itertools import product
# Two iterables
colors = ['red', 'blue']
sizes = ['S', 'M', 'L']
for item in product(colors, sizes):
print(item)
# ('red', 'S')
# ('red', 'M')
# ('red', 'L')
# ('blue', 'S')
# ('blue', 'M')
# ('blue', 'L')
# Three or more iterables
list(product([0, 1], [0, 1], [0, 1]))
# [(0,0,0), (0,0,1), (0,1,0), (0,1,1), (1,0,0), (1,0,1), (1,1,0), (1,1,1)]
# Repeat same iterable
list(product([0, 1], repeat=3))
# Same as product([0,1], [0,1], [0,1])Counting Combinations
from itertools import permutations, combinations, product
from math import factorial, comb
items = ['a', 'b', 'c', 'd']
n = len(items)
r = 2
# Permutations: n! / (n-r)!
num_perms = len(list(permutations(items, r)))
formula = factorial(n) // factorial(n - r)
print(f"Permutations: {num_perms} = {formula}") # 12
# Combinations: n! / (r! * (n-r)!)
num_combs = len(list(combinations(items, r)))
formula = comb(n, r) # Python 3.8+
print(f"Combinations: {num_combs} = {formula}") # 6
# Product: n^r (for repeat=r with n items)
num_products = len(list(product(items, repeat=r)))
print(f"Products: {num_products} = {n**r}") # 16Password Generator
from itertools import product
import string
def generate_passwords(length: int, charset: str = None):
"""Generate all possible passwords of given length."""
if charset is None:
charset = string.ascii_lowercase + string.digits
for combo in product(charset, repeat=length):
yield ''.join(combo)
# Generate 3-character passwords
for i, pwd in enumerate(generate_passwords(3, 'abc')):
print(pwd)
if i >= 10: # Limit output
break
# aaa, aab, aac, aba, abb, abc, aca, acb, acc, baa, babSubset Generation
from itertools import combinations
def all_subsets(items):
"""Generate all subsets (power set)."""
for r in range(len(items) + 1):
yield from combinations(items, r)
for subset in all_subsets(['a', 'b', 'c']):
print(subset)
# ()
# ('a',)
# ('b',)
# ('c',)
# ('a', 'b')
# ('a', 'c')
# ('b', 'c')
# ('a', 'b', 'c')Team Assignment
from itertools import combinations
def assign_teams(players: list, team_size: int):
"""Generate all possible team combinations."""
return combinations(players, team_size)
players = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve']
teams_of_2 = list(assign_teams(players, 2))
print(f"Possible 2-person teams: {len(teams_of_2)}") # 10
for team in teams_of_2:
print(f"Team: {', '.join(team)}")Configuration Testing
from itertools import product
def test_configurations():
"""Test all configuration combinations."""
databases = ['postgres', 'mysql', 'sqlite']
cache_modes = ['enabled', 'disabled']
log_levels = ['debug', 'info', 'error']
for db, cache, log in product(databases, cache_modes, log_levels):
config = {'database': db, 'cache': cache, 'log_level': log}
run_test(config)
# Tests 3 × 2 × 3 = 18 configurationsGrid Coordinates
from itertools import product
# Generate 2D grid coordinates
def grid_coords(width: int, height: int):
return product(range(width), range(height))
for x, y in grid_coords(3, 3):
print(f"({x}, {y})")
# 3D grid
for x, y, z in product(range(2), repeat=3):
print(f"({x}, {y}, {z})")Anagram Finder
from itertools import permutations
def find_anagrams(word: str, dictionary: set) -> list:
"""Find all valid anagrams of a word."""
anagrams = set()
for perm in permutations(word):
candidate = ''.join(perm)
if candidate in dictionary and candidate != word:
anagrams.add(candidate)
return sorted(anagrams)
dictionary = {'cat', 'act', 'tac', 'dog', 'god'}
print(find_anagrams('cat', dictionary)) # ['act', 'tac']Pair Generation
from itertools import combinations
def generate_pairs(items: list):
"""Generate all unique pairs."""
return list(combinations(items, 2))
people = ['Alice', 'Bob', 'Carol', 'Dave']
pairs = generate_pairs(people)
print(f"Number of pairs: {len(pairs)}") # 6
for p1, p2 in pairs:
print(f"{p1} meets {p2}")Tournament Brackets
from itertools import combinations
def round_robin_schedule(teams: list) -> list:
"""Generate round-robin tournament schedule."""
matches = list(combinations(teams, 2))
return matches
teams = ['Team A', 'Team B', 'Team C', 'Team D']
schedule = round_robin_schedule(teams)
print(f"Total matches: {len(schedule)}")
for match_num, (t1, t2) in enumerate(schedule, 1):
print(f"Match {match_num}: {t1} vs {t2}")Binary Strings
from itertools import product
def binary_strings(length: int) -> list:
"""Generate all binary strings of given length."""
return [''.join(bits) for bits in product('01', repeat=length)]
print(binary_strings(3))
# ['000', '001', '010', '011', '100', '101', '110', '111']
# As integers
def binary_values(bits: int) -> list:
return [int(''.join(b), 2) for b in product('01', repeat=bits)]
print(binary_values(3)) # [0, 1, 2, 3, 4, 5, 6, 7]Memory Efficiency
from itertools import permutations
import sys
# Iterators don't store all values
items = list(range(10))
# This would be 3,628,800 tuples in memory
# perm_list = list(permutations(items)) # ~300MB
# Iterator uses constant memory
perm_iter = permutations(items)
print(sys.getsizeof(perm_iter)) # ~100 bytes
# Process one at a time
for p in perm_iter:
process(p)
break # Stop after firstComplexity Reference
| Function | Count | Formula |
|---|---|---|
permutations(n) | n! | factorial(n) |
permutations(n, r) | nPr | factorial(n) // factorial(n-r) |
combinations(n, r) | nCr | comb(n, r) |
combinations_with_replacement(n, r) | comb(n+r-1, r) | |
product(n, repeat=r) | n^r | n ** r |
Itertools combinatorics generate possibilities lazily—essential when working with large sets where materializing all combinations would exhaust memory.
React to this post: