
module Enumerable

  # Produces an array of arrays of all possible combinations
  # of the given arrays in the positions given. (Imagine
  # it like a slot machine dial. This gives evey combination
  # that could come up.)
  #
  #   a = %w|a b|
  #   b = %w|a x|
  #   c = %w|x y|
  #   Array.combinations(a, b, c).each { |x| p x }
  #
  # produces
  #
  #   ["a", "a", "x"]
  #   ["a", "a", "y"]
  #   ["a", "x", "x"]
  #   ["a", "x", "y"]
  #   ["b", "a", "x"]
  #   ["b", "a", "y"]
  #   ["b", "x", "x"]
  #   ["b", "x", "y"]
  #
  def self.combinations(head, *rest)
    crest = rest.empty? ? [[]] : combinations(*rest)
    head.inject([]) { |combs, item|
      combs + crest.map { |comb| [item] + comb }
    }
  end

end


#  _____         _
# |_   _|__  ___| |_
#   | |/ _ \/ __| __|
#   | |  __/\__ \ |_
#   |_|\___||___/\__|
#
=begin test

  require 'test/unit'

  class TCEnumerable < Test::Unit::TestCase

    def test_01
      a = [1,2]
      b = [3,4]
      z = Enumerable.combinations(a,b)
      r = [[1,3],[1,4],[2,3],[2,4]]
      assert_equal( r, z )
    end

    def test_02
      a = %w|a b|
      b = %w|a x|
      c = %w|x y|
      z = Enumerable.combinations(a, b, c)
      r = [ ["a", "a", "x"],
            ["a", "a", "y"],
            ["a", "x", "x"],
            ["a", "x", "y"],
            ["b", "a", "x"],
            ["b", "a", "y"],
            ["b", "x", "x"],
            ["b", "x", "y"] ]
      assert_equal( r, z )
    end

  end

=end
