"Harry Ohlsen" <> schrieb im Newsbeitrag
news:...
> Robert Klemme wrote:
>
> > Ah, similar idea but nicer coding.
>
> Coming from you, that's a much appreciated compliment!
You're welcome!
> > I like especially your calculation of
> > the counting range and int[idx] as bit test. I didn't know that one.
>
> I discovered during a re-browse of pickaxe a couple of months ago, but
this is the first time I've actually had a chance to use it.
>
> > Btw, you don't need the test for length 0 if you do
> >
> > for n in 1 ... (2<<length) do
>
> Good point.
>
> Something I was thinking about was that the power set (set of subsets)
becomes large very quickly (obvious from the "2 << length", I guess). It
might be nice to have an iterator, too. The method that returns the
collection of subsets could then just use it.
Another good point!
> Something like this (I've removed the empty set test, since I think this
is cleaner in a mathematical sense) ...
That might be handled by an additional flag with a default value (which
one, the mathematical or the practical?). Practically you often don't
need / want the empty set.
Funny to see how this evolves. My current vesion looks like this:
module Enumerable
def each_subset(skip_empty = false)
for n in (skip_empty ? 1 : 0) ... (1 << size) do
subset = []
each_with_index do |elem, i|
subset << elem if n[i]
end
yield subset
end
self
end
def powerset(skip_empty = false)
subsets = []
each_subset(skip_empty) { |s| subsets << s }
return subsets
end
end
Changes / Improvements:
- self[index] is not used since it is not available with all Enumerables
- flag 'skip_empty' added
- self returned from iterator
- renamed #subsets to #powerset (this is the mathematical correct term,
isn't it)
- changed (2 << length - 1) to (1 << length)
Here's another experimental version that works even if #size is not
supported. This really needs only #each. Alternatively one could do an
initial iteration to calculate the size - that saves the intermediate
array.
module Enumerable
def each_subset(skip_empty = false)
enum = respond_to?( :size ) ? self : to_a
for n in (skip_empty ? 1 : 0) ... (1 << enum.size) do
subset = []
enum.each_with_index do |elem, i|
subset << elem if n[i] == 1
end
yield subset
end
self
end
def powerset(skip_empty = false)
subsets = []
each_subset(skip_empty) { |s| subsets << s }
return subsets
end
end
# test class
class Test
include Enumerable
def initialize(n); @n=n; end
def each; @n.times {|c| yield c}; self; end
end
p Test.new(3).powerset
Kind regards
robert