Решение dmarkow (я считаю) материализует диапазоны, которые, по крайней мере в теории, используют больше памяти, чем вам нужно.Вот способ сделать это без материализации диапазонов:
def magic(ranges, &block)
magic_ = lambda do |ranges, args, pos, block|
if pos == ranges.length
block.call(*args)
else
ranges[pos].each do |i|
args[pos] = i
magic_.call(ranges, args, pos+1, block)
end
end
end
magic_.call(ranges, [nil]*ranges.length, 0, block)
end
magic([1..10] * 4) do |a,b,c,d|
puts [a, b, c, d].inspect
end
Тем не менее, производительность - это сложная вещь, и я не знаю, насколько эффективен Ruby с вызовами функций, поэтому, возможно, придерживаться библиотечных функцийсамый быстрый путь.
Обновление : взял предложение Phrogz и поместил magic_
внутри magic
.( Обновление : принял предложение Phrogz снова и, надеюсь, сделал это правильно на этот раз с lambda
вместо def
).
Обновление : Array#product
возвращает Array
, поэтому я предполагаю, что это полностью материализовано.У меня нет Ruby 1.9.2, но Младен Ябланович отметил, что Array#repeated_permutation
, вероятно, не материализует все это (даже при том, что начальный диапазон материализован с to_a
).