Combinations with Loops vs itertools.combinations in Python 2026 with Efficient Code
Generating combinations is a common task in programming, but using nested loops is inefficient and hard to maintain. In 2026, using itertools.combinations is the standard, clean, and highly efficient way to generate combinations in Python.
This March 15, 2026 guide shows why you should stop using manual combination loops and how to use itertools.combinations effectively.
TL;DR — Key Takeaways 2026
- Never use nested loops for generating combinations — use
itertools.combinations combinations()is memory-efficient and returns an iterator- It generates combinations in lexicographic sort order
- Works with any iterable and supports choosing r items
- Much faster and cleaner than manual nested loops
1. The Old Way (Avoid in 2026)
# ❌ Bad: Manual nested loops
items = ['A', 'B', 'C', 'D']
combs = []
for i in range(len(items)):
for j in range(i+1, len(items)):
combs.append((items[i], items[j]))
print(combs)
2. The Modern Efficient Way
from itertools import combinations
items = ['A', 'B', 'C', 'D']
# ✅ Best way in 2026
combs = list(combinations(items, 2))
print(combs)
# [('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
3. Advanced Usage Patterns
# Combinations of different lengths
team = ["Alice", "Bob", "Carol", "Dave"]
# All pairs
pairs = list(combinations(team, 2))
# All groups of 3
groups = list(combinations(team, 3))
# With indices
for i, combo in enumerate(combinations(team, 2), start=1):
print(f"Combination {i}: {combo}")
# Real-world: Choosing toppings
toppings = ["cheese", "pepperoni", "mushroom", "onion"]
for combo in combinations(toppings, 3):
print(combo)
4. Why itertools.combinations is Better
| Aspect | Manual Loops | itertools.combinations |
|---|---|---|
| Readability | Poor | Excellent |
| Performance | Slow | Very Fast (C implementation) |
| Memory Usage | High if storing all | Lazy iterator |
| Flexibility | Limited | Works with any iterable |
Why Nested Loops Fall Short
Generating all pairs with nested loops requires careful index handling to avoid pairing an item with itself and to avoid producing both (a, b) and (b, a). Each extra level of nesting adds another loop and another chance for mistakes.
itertools.combinations(items, r) returns every unique group of r items in their original order, with no repeats. It is shorter, runs its loops in C and makes the intent obvious.
The number of combinations grows quickly: n items give n*(n-1)/2 pairs, so check the count before generating very large sets.
Worked Example: Loops versus combinations
We produce all pairs of products both ways and confirm they match.
from itertools import combinations
from math import comb
items = ["pen", "book", "lamp", "mug"]
loop_pairs = []
for i in range(len(items)):
for j in range(i + 1, len(items)):
loop_pairs.append((items[i], items[j]))
tool_pairs = list(combinations(items, 2))
print(loop_pairs == tool_pairs)
print(len(tool_pairs), comb(4, 2))
print(comb(1000, 2), "pairs for 1000 items")
Both methods produce the same six pairs in the same order. math.comb reports the count without generating anything, showing that 1,000 items would already produce 499,500 pairs.
Practical Tips
If you only need to test each pair, loop over combinations directly instead of building a list. This keeps memory flat even when the number of pairs is large.
For numeric data, NumPy broadcasting can sometimes replace pair generation entirely. For example, a distance matrix between points can be computed with array operations instead of looping over every pair, which is much faster for hundreds of items. Use combinations when the items are general Python objects or when the per-pair logic is complex.
Remember that combinations treats items by position, not value, so a list with repeated values produces repeated pairs. Remove duplicates with set() first if each distinct value should appear only once.
Common Mistakes
- Starting the inner loop at 0 and producing duplicate pairs.
- Generating huge combination lists in memory.
- Confusing combinations with permutations.
- Not checking the count with math.comb first.
Quick Summary
- combinations replaces nested index loops.
- Pairs are unique and in input order.
- math.comb predicts the count.
- Use permutations when order matters.
Conclusion — Stop Using Loops for Combinations in 2026
Manual nested loops for generating combinations are an anti-pattern in modern Python. In 2026, itertools.combinations is the clear winner — it is faster, cleaner, more readable, and memory-efficient. Using it is considered a basic best practice for writing efficient code.
Next steps:
- Replace all manual combination loops in your codebase with
itertools.combinations