What is the difference between itertools.permutations and itertools.combinations?
answer
- One cares about arrangement, one does not
- Three letters, pairs: six versus three
- r! permutations per single combination
- math.perm and math.comb count without iterating
- Selection is positional, never by value
basics
~20 sitertools.permutations treats order as significant, so ('a','b') and ('b','a') are both yielded. itertools.combinations yields each selection once, keeping the input's own order. For n items taken r at a time that is n!/(n-r)! tuples versus n!/(r!(n-r)!).
solid answer
~40 sBoth take an iterable and a length `r` and yield tuples lazily, but they differ on whether arrangement counts. `itertools.permutations('abc', 2)` yields six tuples, including both `('a','b')` and `('b','a')`, because it enumerates ordered arrangements. `itertools.combinations('abc', 2)` yields three — `('a','b')`, `('a','c')`, `('b','c')` — one per unordered selection, always emitting the chosen elements in the order they appeared in the input. The counts are the familiar formulas: n!/(n-r)! for permutations and n!/(r!(n-r)!) for combinations, computable without running anything via `math.perm` and `math.comb`. Both select by position rather than by value, so neither deduplicates equal elements. Reach for combinations when the result is a set-like choice (which two servers to drain) and permutations when the arrangement itself is the answer (in which order to visit them).
code
python · 5 linesfrom itertools import permutations, combinations
items = ["a", "b", "c"]
print(list(permutations(items, 2)))
print(list(combinations(items, 2)))go deeper
Recall that permutations counts orderings and combinations does not, and be able to write both calls for a three-letter string and say how many tuples each returns.
Explain the two count formulas, that output order mirrors input order rather than being sorted, and that both select by position so equal elements produce duplicate tuples.
Show the instinct to size the enumeration with math.perm or math.comb before iterating, and explain that laziness bounds memory but never runtime.
Frame the choice as a modelling decision: picking permutations where combinations was meant multiplies the work by r! and silently returns rearrangements as if they were distinct results.
### The two questions they answer Every combinatorial enumeration starts with one decision: **does the arrangement of the chosen elements matter?** `itertools.permutations` says yes; `itertools.combinations` says no. Everything else about the two functions — their signatures, their laziness, their ordering, their output counts — follows from that single distinction. Both have the shape `f(iterable, r=None)`. They pull the whole input into an internal tuple up front, then yield tuples of length `r` one at a time. For `permutations`, `r` defaults to the full length of the input; `combinations` requires `r` explicitly. ```python from itertools import permutations, combinations items = ['a', 'b', 'c'] list(permutations(items, 2)) # [('a','b'), ('a','c'), ('b','a'), ('b','c'), ('c','a'), ('c','b')] list(combinations(items, 2)) # [('a','b'), ('a','c'), ('b','c')] ``` The permutation list contains three extra tuples: each combination appears in both of its orderings. In general each combination of size r corresponds to r! permutations, which is exactly why the two count formulas differ by that factor. ### The counts, and why they matter more than the API For n input elements taken r at a time: * permutations: n! / (n - r)! — the number of ordered arrangements. * combinations: n! / (r! (n - r)!) — the binomial coefficient, usually written C(n, r). The standard library will compute both for you without generating anything: `math.perm(n, r)` and `math.comb(n, r)`. This is the habit worth forming — before writing a loop over one of these iterators, evaluate its size. `math.comb(52, 5)` is 2,598,960, a fine thing to iterate. `math.perm(20, 20)`, which is 20!, is about 2.4 x 10^18, and no amount of laziness makes that loop terminate. ### Ordering of the output Neither function sorts. Both walk index positions of the internal input tuple in increasing order, so the output order is a function of **input order**, not of value. If the input is already sorted, the output tuples come out in lexicographic order — which is why textbook examples always look sorted. Feed unsorted input and you get unsorted output, in a completely deterministic order that mirrors the input's own sequence. A direct consequence: **selection is positional, not value-based.** If the input contains equal elements, the output contains equal tuples. `combinations(['a','a','b'], 2)` yields `('a','a')`, `('a','b')` and `('a','b')` — two identical pairs, because the two `'a'` values sit at different positions. Neither function has any notion of a set. ### Laziness and memory Both return iterators, so nothing is precomputed: memory is the input tuple plus one output tuple plus a small array of indices. That means the memory cost is trivial even for astronomically large enumerations — and it is precisely why the runtime trap is so easy to fall into. Laziness bounds memory, never time. A `for` loop over `permutations` of twenty things will still be running long after everyone has gone home. Because the input is drained into a tuple immediately, passing a generator to either function consumes it in full before the first tuple is yielded, and passing an endless iterator hangs at construction rather than at the first `next()`. ### Choosing between them The test is a sentence: read the problem statement and ask whether swapping two chosen elements produces a different answer. * Which two of these five fee codes appear together on the same invoice? Order is meaningless — `combinations`. * In what sequence do we apply three discounts to a line item? Order changes the total — `permutations`. * Every possible assignment of one of three tiers to each of four accounts? That is neither: it is a Cartesian product, `itertools.product` with `repeat=4`. Getting this wrong is a silent bug, not a crash: an enumeration using `permutations` where `combinations` was meant simply does r! times the work and reports duplicated results that differ only in arrangement, which is easy to miss when the downstream code aggregates. ### Interview framing Interviewers ask this as a screen because it merges three things a working engineer needs: knowing the stdlib exists rather than hand-rolling recursion, recalling the two counting formulas, and having the instinct to estimate the output size before iterating it. A complete answer names both functions, shows a three-element example, states both formulas, and adds that the output order follows input order and that neither deduplicates.
- How many tuples does itertools.permutations(range(10), 3) yield, and how would you work that out without running it?720 — that is 10!/(10-3)! = 10 x 9 x 8. `math.perm(10, 3)` returns it directly, and `math.comb(10, 3)` returns 120, the same enumeration with order ignored; the ratio is 3! = 6. Computing the count first is the habit that stops an enumeration from being started and then abandoned.
- What does itertools.permutations do when you omit the second argument?`r` defaults to the full length of the input, so it yields every full-length arrangement — n! tuples. That default is a common accident: `permutations(items)` on a ten-element list is 3,628,800 tuples, while the author usually meant pairs. `itertools.combinations` has no such default and requires `r`.
- Do either of these functions remove duplicate results when the input contains equal elements?No. Both select by position, not by value, so equal input elements produce equal output tuples. `combinations(['a','a','b'], 2)` yields `('a','b')` twice. If you need distinct results, deduplicate the input first, or collect the output into a set — accepting that the enumeration still does the full amount of work.
Combinations are who you invite to dinner; permutations are where each guest sits. The same guest list seats many different ways.
saying these in an interview costs you the question
- Says combinations sorts its output regardless of input order
- Claims either function deduplicates equal input elements
- Thinks permutations and combinations yield the same number of tuples
- Believes laziness makes a factorial enumeration cheap to run
- Confuses combinations with the Cartesian product of several iterables
- Cannot state either count formula even approximately