class Array

Public Instance Methods

comprehension() { |self| ... } click to toggle source

Iterates over each permutation of the enumerable values within the {Array}.

@yield [list]

The given block will be passed each permutation of the enumerable
values in the {Array}.

@yieldparam [Array] list

A permutation of the enumerable values within the {Array}.

@return [Enumerator]

If no block is given, an enumerator object will be returned.

@example

[(1..5),(1..4),(1..3)].comprehension.to_a
# => [
  [1, 1, 1], [1, 1, 2], [1, 1, 3],
  [1, 2, 1], [1, 2, 2], [1, 2, 3],
  [1, 3, 1], [1, 3, 2], [1, 3, 3],
  [1, 4, 1], [1, 4, 2], [1, 4, 3],
  [2, 1, 1], [2, 1, 2], [2, 1, 3],
  [2, 2, 1], [2, 2, 2], [2, 2, 3],
  [2, 3, 1], [2, 3, 2], [2, 3, 3],
  [2, 4, 1], [2, 4, 2], [2, 4, 3],
  [3, 1, 1], [3, 1, 2], [3, 1, 3],
  [3, 2, 1], [3, 2, 2], [3, 2, 3],
  [3, 3, 1], [3, 3, 2], [3, 3, 3],
  [3, 4, 1], [3, 4, 2], [3, 4, 3],
  [4, 1, 1], [4, 1, 2], [4, 1, 3],
  [4, 2, 1], [4, 2, 2], [4, 2, 3],
  [4, 3, 1], [4, 3, 2], [4, 3, 3],
  [4, 4, 1], [4, 4, 2], [4, 4, 3],
  [5, 1, 1], [5, 1, 2], [5, 1, 3],
  [5, 2, 1], [5, 2, 2], [5, 2, 3],
  [5, 3, 1], [5, 3, 2], [5, 3, 3],
  [5, 4, 1], [5, 4, 2], [5, 4, 3]
]
# File lib/combinatorics/list_comprehension.rb, line 44
def comprehension
  return enum_for(:comprehension) unless block_given?

  if empty?
    yield self
    return nil
  end

  enums = self.map do |value|
    case value
    when Combinatorics::Enumerator
      value
    when Enumerable
      value.enum_for
    else
      [value].enum_for
    end
  end

  iteration = enums.map { |e| e.next }

  loop do
    yield iteration.dup

    (enums.length - 1).downto(0) do |index|
      begin
        iteration[index] = enums[index].next
        break
      rescue StopIteration
        enums[index].rewind
        iteration[index] = enums[index].next
      end

      return nil if index == 0
    end
  end
end