rubyguides

Array#permutation

arr.permutation(n) { |p| block }

Array#permutation generates all possible ordered arrangements of array elements of a given size. This method is essential for solving combinatorial problems, generating test cases, and exploring mathematical relationships in your data.

Syntax

array.permutation(n) { |p| block }

Returns an Enumerator when called without a block, allowing you to chain other Enumerable methods or convert to an array.

Parameters

ParameterTypeDefaultDescription
nIntegerRequiredThe size of each permutation to generate

Examples

Basic usage

# Generate all permutations of 2 elements
[1, 2, 3].permutation(2).to_a
# => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]

This basic example returns all six possible two-element orderings from a three-element array. Unlike combination, the order of each pair matters here, so both [1, 2] and [2, 1] appear. That doubled output is the tradeoff you accept when sequence carries meaning and both directions need to be considered.

With a block

# Using a block with permutation
[1, 2].permutation(2) do |p|
  puts "Permutation: #{p.join(', ')}"
end
# Permutation: 1, 2
# Permutation: 2, 1

The block form lets you process each permutation as it is generated rather than collecting them all into a single array. This is useful when you want to check a condition and stop early — break out of the block once you find a match, avoiding the cost of generating every remaining arrangement.

Practical examples

# Find all possible orders for scheduling 3 tasks
tasks = [:design, :code, :test]
schedules = tasks.permutation(3).to_a
# => [[:design, :code, :test], [:design, :test, :code],
#     [:code, :design, :test], [:code, :test, :design],
#     [:test, :design, :code], [:test, :code, :design]]

The scheduling example above produces all 6 possible task orderings from a set of 3, which is exactly what a brute-force search through every sequence would need. When the number of tasks grows, the result set expands factorially, so this pattern works best with small lists or when combined with early termination inside the block.

Common Patterns

Generating all possible orderings

letters = [a, b, c]
letters.permutation(2).to_a
# => [["a", "b"], ["a", "c"], ["b", "a"], ["b", "c"], ["c", "a"], ["c", "b"]]

Notice the difference from combination: here [“a”, “b”] and [“b”, “a”] both appear because order matters in a permutation. This distinction is the core reason to pick permutation over combination — when the sequence itself carries meaning, you need both orderings in the result. The method gives you every arrangement with no extra bookkeeping on your part.

Finding unique arrangements

# Get all 3-letter arrangements from a set of letters
[A, B, C, D].permutation(3).to_a
# Returns 24 possible ordered arrangements

This example produces 24 results because P(4,3) = 4!/(4-3)! = 24. Each arrangement preserves order from the original array, so both [A, B, C] and [A, C, B] appear. This demonstrates how quickly the result set can grow even with small inputs, making it important to check input sizes before requesting a full enumeration.

Error Cases

# Negative size raises ArgumentError
[1, 2, 3].permutation(-1)
# => ArgumentError: negative permutation size (-1)

# Size greater than array length returns empty enumerator
[1, 2].permutation(5).to_a
# => []

# Size equal to zero returns single empty array
[1, 2, 3].permutation(0).to_a
# => [[]]

thinking in permutations

permutation is the right tool when order matters and every arrangement should be considered. That makes it useful for scheduling, search problems, and test generation where the sequence itself changes the meaning of the result. The method keeps the logic focused on the combinations of order rather than on the bookkeeping needed to build them by hand.

Because the result set can grow very quickly, it is a good idea to check the size of the input before reaching for the full enumeration. That keeps the code honest about how much work it is about to do and helps the reader understand why the loop exists at all. When the search space is large, a smaller sample or a stricter filter may be the better choice.

watching the search space carefully

permutation can be a great teaching tool because it makes the cost of order visible. Even a small array can produce many results, so the surrounding code should have a clear reason for asking for every arrangement. If the goal is only to compare a few candidates, a simpler loop may be easier to read and much cheaper to run. When the full set really is needed, keeping the input small is the best way to keep the example and the runtime sensible.

See Also