Generate All Combinations Of Array Elements Without Repetition In Ruby
Picking every possible pair of players, every three-item bundle from a catalogue, every subset of feature flags — these are combinations, and Ruby has them built in. No manual nested loops required.
Description
combination(n) yields every unordered selection of n elements. Order doesn’t matter, so [1, 2] and [2, 1] count as the same combination and only one appears.
permutation(n) is the ordered version, where [1, 2] and [2, 1] are both produced. Use combination for teams and subsets, permutation for orderings and arrangements.
Both return an Enumerator when called without a block, so .to_a materializes them and .lazy lets you take the first few without generating all of them — which matters, because the counts grow fast.
Sample input:
[:a, :b, :c, :d].combination(2).to_a
Sample Output:
# => [[:a, :b], [:a, :c], [:a, :d], [:b, :c], [:b, :d], [:c, :d]]
Answer
items = [:a, :b, :c, :d]
items.combination(2).to_a
# => [[:a,:b], [:a,:c], [:a,:d], [:b,:c], [:b,:d], [:c,:d]]
items.combination(3).to_a
# => [[:a,:b,:c], [:a,:b,:d], [:a,:c,:d], [:b,:c,:d]]
# Every possible subset, including empty and full
(0..items.size).flat_map { |n| items.combination(n).to_a }
# => [[], [:a], [:b], ..., [:a,:b,:c,:d]]
# Ordered arrangements instead
items.permutation(2).to_a
# => [[:a,:b], [:b,:a], [:a,:c], ...]
# Combinations across two different arrays
[:small, :large].product([:red, :blue])
# => [[:small,:red], [:small,:blue], [:large,:red], [:large,:blue]]
# Lazy — don't build 2_598_960 hands to look at three
(1..52).to_a.combination(5).lazy.first(3)
# Count without generating
def n_choose_k(n, k) = (1..k).reduce(1) { |acc, i| acc * (n - i + 1) / i }
n_choose_k(52, 5) # => 2598960
Check viewARU - Brand Newsletter!
Newsletter to DEVs by DEVs - boost your Personal Brand & career! 🚀