1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
unless Array.method_defined? :product
require 'backports/tools/arguments'
class Array
def product(*arg)
# Implementation notes: We build a block that will generate all the combinations
# by building it up successively using "inject" and starting with one
# responsible to append the values.
#
result = []
arg.map!{|ary| Backports.coerce_to_ary(ary)}
n = arg.inject(size) { |p, a| p * a.size }
return [] if n == 0
raise RangeError, "too big a product" if n > 1<<31
arg.reverse! # to get the results in the same order as in MRI, vary the last argument first
arg.push self
outer_lambda = arg.inject(result.method(:push)) do |proc, values|
lambda do |partial|
values.each do |val|
proc.call(partial.dup << val)
end
end
end
outer_lambda.call([])
result
end
end
end
|