I would like to generate a powerset of a rather big set (about 30-50 elements) and I know that it takes 2^n
to store the powerset.
Is it possible to gen
This uses the standard "bit array" trick for generating power sets (and it uses the fact that Ruby's Integer
s behave as bit arrays). But more importantly, it uses an Enumerator
to generate the sets lazily.
require 'set'
module Enumerable
def powerset
number_of_sets = 2 ** count
Enumerator.new {|ps|
number_of_sets.times {|i|
ps << Set[*reject.with_index {|_, j| i[j].zero? }]
}
}
end
end
This works perfectly fine even for thousands of elements:
enum = (1..10_000).powerset
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
enum.next # => #
# ...
EDIT: This is based on @steenslag's solution. I totally forgot about Array#combination
, since I was too focused on finding a solution that would work for any Enumerable
. However, my solution requires that the Enumerable
be finite anyway, and any finite Enumerable
should probably be representable as an Array
, so that's not much of a restriction.
module Enumerable
def powerset
ary = to_a
Enumerator.new {|ps|
ary.size.times {|n|
ary.combination(n).each(&ps.method(:yield))
}
}
end
end