Fast powerset function
Evan Klitzke
evan at yelp.com
Fri Jul 13 02:53:02 EDT 2007
On 7/12/07, Evan Klitzke <evan at yelp.com> wrote:
> On 7/12/07, Arash Arfaee <Arash at ece.ucsb.edu> wrote:
> > I need a powerset generator function. It's really slow with recursion. Does
> > anybody have any idea or code(!!) to do it in an acceptable time?
> > Thanks
> > -Arash
>
> I thought that this was a really interesting question, so I wrote up a
> solution that doesn't use recursion. I didn't test it a whole lot, but
> I'm pretty sure it works -- let me know if there are any oversights or
> if you can make any improvements ;-) Also, not sure if the line breaks
> will be mangled by my mail client, so bear with me if there are any
> errors.
>
> def fact(n):
> '''Factorial'''
> r = 1
> for i in xrange(1, n + 1):
> r *= i
> return r
>
> def nCr(n, r):
> '''Number of combinations of r items from n things'''
> return fact(n) / (fact(r) * fact(n - r))
>
> def get_combinations(slots, tokens):
> '''A generator yielding combinations from slots of size tokens'''
> maxcombos = nCr(len(slots), tokens)
> for index in xrange(maxcombos):
> token_copy = tokens
> combo = []
> for val in xrange(1, len(slots) + 1):
> if not token_copy:
> break
> thresh = nCr(len(slots) - val, token_copy - 1)
> if index < thresh:
> combo.append(slots[val-1])
> token_copy -= 1
> else:
> index -= thresh
> yield tuple(combo)
>
> def powerset(s):
> '''Returns the powerset of s'''
> pset = set()
> for num_tokens in xrange(1, len(s)):
> for combo in get_combinations(s, num_tokens):
> pset.add(combo)
> # These two are special cases
> pset.add(s)
> pset.add(tuple())
> return pset
>
> if __name__ == '__main__':
> print powerset((1, 2, 3, 4))
One more obvious thing that I omitted. You can make this a lot faster
by caching the values of nCr. This is a simple modification, that I'll
leave to the reader ;-)
--
Evan Klitzke <evan at yelp.com>
More information about the Python-list
mailing list