[Tutor] Re: recursion and power sets

Thorsten Kampe thorsten at thorstenkampe.de
Tue Apr 27 07:15:29 EDT 2004


* alice (2004-03-07 06:30 +0100)
> I was trying to write a function that would take a set - represented as a list 
> with non repeating elements - and return the power set, so given:
> 
> [1,2,3]
> 
> it should return:
> 
> [[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
> 
> After much general confusion, this is what I eventually came up with:
> 
> def foo(pool,head,result,n):
>     """ pool, head and result should be lists, n a positive integer """
>     if (n == 0):
>        while (pool != []):
>              head.append(pool.pop())
>              result.append(head[:])
>              head.pop()
>     else:
>        while (pool != []):
>              head.append(pool.pop())
>              foo(pool[:],head,result,n-1)
>              head.pop()
> 
> def power(set):
>     head = []
>     result = [[]]
>     for i in range(len(set)):
>         foo(set[:],head,result,i)
>     return result
> 
> This gives the subsets in a simmilar order to the one in which I would find 
> them if I was doing it by hand, but its kind of difficult to think about, so 
> I thought about it a bit more and came up with:
> 
> def power(set):
>     result = []
>     bits = len(set)
>     for string in range(2**bits):
>         subset = []
>         position = 0
>         while (string > 0):
>               if (string % 2 != 0):
>                  subset.append(set[position])
>               string /= 2
>               position += 1
>         result.append(subset)
>     return result
> 
> Even though this algorithm gives the subsets in a completely different order 
> to the way I'd normally find them by hand, I'm guessing its closer to the 
> "canonical" algorithm for finding power sets than my recursive attempt, am I 
> right? or is there a third, completely different way of doing this?

Catching up...

def powerset(seq):
    if len(seq):
        head = powerset(seq[:-1])
        return head + [item + [seq[-1]] for item in head]
    else:
        return [[]]
        
Do not mix the sorting task with the plain "powersetting"! If you want
to have the powerset sorted like you prefer, you should use a
multipurpose "function sort": first by value and then by length. The
standard Python sort() already sort sequences by value.

def funcsort(seq, func):
    """ sort seq by func(item) """
    seq = seq[:]
    seq.sort(lambda x, y: cmp(func(x), func(y)))
    return seq

With these two functions your task is trivial:

>>> power_set = powerset([1, 2, 3])        # create the powerset
>>> power_set.sort()                       # sort the powerset by value
>>> funcsort(power_set, lambda x: len(x))  # sort the powerset by length


Thorsten




More information about the Tutor mailing list