A combination is a selection of items where order doesn't matter-{A, B} is the same as {B, A}. Python's itertools module provides efficient tools for generating combinations.
Using itertools.combinations
The standard library solution is fast and memory-efficient:
from itertools import combinations
items = ['A', 'B', 'C', 'D']
pairs = list(combinations(items, 2))
print(pairs)
triplets = list(combinations(items, 3))
print(triplets)The function returns an iterator, so wrap with list() only when needed.
Combinations with Replacement
Allow elements to repeat using combinations_with_replacement:
from itertools import combinations_with_replacement
items = ['A', 'B', 'C']
result = list(combinations_with_replacement(items, 2))
print(result)Practical Examples
Finding All Subsets of Size k
from itertools import combinations
def subsets_of_size(items, k):
"""Generate all subsets of exactly size k."""
return [set(combo) for combo in combinations(items, k)]
print(subsets_of_size([1, 2, 3, 4], 2))Team Pairing
from itertools import combinations
players = ["Alice", "Bob", "Charlie", "Diana"]
for player1, player2 in combinations(players, 2):
print(f"{player1} vs {player2}")Output:
Alice vs Bob
Alice vs Charlie
Alice vs Diana
Bob vs Charlie
Bob vs Diana
Charlie vs DianaSum Combinations
from itertools import combinations
numbers = [1, 2, 3, 4, 5]
target = 7
pairs = [(a, b) for a, b in combinations(numbers, 2) if a + b == target]
print(pairs)Output:
[(2, 5), (3, 4)]Manual Implementation (Educational)
Understanding the recursive approach helps in interviews:
def generate_combinations(items, r):
"""Generate combinations using pick/skip recursion."""
if r == 0:
return [[]]
if not items:
return []
first, rest = items[0], items[1:]
with_first = [[first] + combo for combo in generate_combinations(rest, r - 1)]
without_first = generate_combinations(rest, r)
return with_first + without_first
print(generate_combinations(['A', 'B', 'C'], 2))Output:
[['A', 'B'], ['A', 'C'], ['B', 'C']]Iterative Implementation
Avoid recursion limits with an iterative approach:
def combinations_iterative(items, r):
"""Generate combinations iteratively using indices."""
n = len(items)
if r > n:
return []
indices = list(range(r))
result = [tuple(items[i] for i in indices)]
while True:
for i in range(r - 1, -1, -1):
if indices[i] != i + n - r:
break
else:
return result
indices[i] += 1
for j in range(i + 1, r):
indices[j] = indices[j - 1] + 1
result.append(tuple(items[i] for i in indices))
return resultCounting Combinations
Calculate how many combinations exist without generating them:
from math import comb # Python 3.8+
print(comb(5, 2)) # 10 combinations of 5 items taken 2 at a time
print(comb(10, 3)) # 120 combinations
from math import factorial
def count_combinations(n, r):
return factorial(n) // (factorial(r) * factorial(n - r))Output:
10
120All Possible Subset Sizes
Generate combinations of all sizes (power set excluding empty set):
from itertools import combinations
def all_combinations(items):
"""Generate combinations of all sizes."""
result = []
for r in range(1, len(items) + 1):
result.extend(combinations(items, r))
return result
print(all_combinations(['A', 'B', 'C']))Output:
[('A',), ('B',), ('C',), ('A', 'B'), ('A', 'C'), ('B', 'C'), ('A', 'B', 'C')]Combinations vs Permutations
| Concept | Order Matters? | [A,B] vs [B,A] |
Function |
|---|---|---|---|
| Combination | No | Same | combinations() |
| Permutation | Yes | Different | permutations() |
from itertools import combinations, permutations
items = ['A', 'B', 'C']
print(list(combinations(items, 2)))
print(list(permutations(items, 2)))Performance Comparison
| Method | Speed | Memory | Stack Safe |
|---|---|---|---|
itertools.combinations |
⚡ C-optimized | Low (iterator) | ✅ Yes |
| Recursive | 🐢 Slow | High | ❌ Risk |
| Iterative | Medium | High | ✅ Yes |
Summary
Use itertools.combinations() for production code-it's fast, memory-efficient, and handles edge cases.
- The recursive "pick or skip" implementation is useful for understanding the algorithm and coding interviews.
- For combinations with repeated elements, use
combinations_with_replacement().