What is the time complexity of Ruby's built in permutation and repeated_permutation methods?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Ruby's permutation and repeated_permutation methods are expensive because they generate enormous output sets. The right way to analyze them is by counting how many sequences they must produce, then multiplying by the work required to build each yielded permutation.
permutation Complexity
If you call array.permutation(r), Ruby generates ordered selections of length r without reuse. The number of results is:
P(n, r) = n! / (n - r)!
where n is the array length.
If each yielded permutation contains r elements, then the overall time is proportional to the number of permutations times the cost to materialize each one. That gives a practical complexity of:
O(P(n, r) * r)
For the common full-length case where r = n, this becomes:
O(n! * n)
That is sometimes shortened informally to factorial time, but the extra * n matters if you care about the cost of constructing or copying each output array.
repeated_permutation Complexity
array.repeated_permutation(r) allows reuse of elements, so the number of outputs is:
n^r
Each yielded result still contains r elements, so the practical complexity is:
O(n^r * r)
That grows extremely fast even for modest n and r.
A Small Ruby Example
The methods themselves are easy to call:
For permutation(2) on three items, Ruby yields 3 * 2 = 6 results. For repeated_permutation(2), it yields 3^2 = 9 results.
That simple example already shows why repeated permutations can explode quickly.
Why the Output Size Dominates
There is no way to generate all permutations faster than the size of the output itself. If your code asks for millions of permutations, the runtime must at least visit millions of results.
That means the complexity is output-bound. Ruby's internal implementation details matter for constant factors, but they do not change the fundamental combinatorial growth.
This is also why the methods feel fine on tiny arrays and then become unusable suddenly. The growth is not linear or quadratic. It is factorial or exponential depending on which method you call.
Memory Use Depends on How You Consume the Results
If you iterate with a block, Ruby can yield one permutation at a time:
That avoids storing every result at once. But if you convert the enumerator to an array, memory usage explodes along with the output count:
So the time cost is inherent, while the memory cost depends partly on whether you stream the outputs or collect them all.
Practical Guidance
Use these methods only when the input size is small enough that the output count is acceptable. If you merely need to count combinations or test whether some arrangement exists, there is often a better algorithm than enumerating everything.
That is especially true for repeated_permutation, where n^r grows quickly even when r is moderately large.
Common Pitfalls
- Saying the complexity is just
O(n!)without accounting for permutation length and output construction cost. - Forgetting that
permutation(r)is smaller than full-lengthpermutation(n). - Treating
repeated_permutation(r)like a minor variation when its output count isn^r. - Converting the enumerator to an array and then being surprised by memory usage.
- Using permutation generation when the real problem could be solved without enumerating every ordering.
Summary
- '
permutation(r)producesn! / (n - r)!outputs, so the practical time cost isO(P(n, r) * r).' - Full-length permutations therefore cost about
O(n! * n). - '
repeated_permutation(r)producesn^routputs, givingO(n^r * r)time.' - The output size dominates both methods, so combinatorial growth is the real problem.
- Stream permutations with a block when possible instead of collecting them all in memory.

