user3581050
user3581050

Reputation: 13

Powerset with frozenset in Python

I'm sitting here for almost 5 hours trying to solve the problem and now I'm hoping for your help.

Here is my Python Code:

   def powerset3(a):

       if (len(a) == 0):
           return frozenset({})
       else:
           s=a.pop()
           b=frozenset({})
           b|=frozenset({})
           b|=frozenset({s})
           for subset in powerset3(a):

              b|=frozenset({str(subset)})
              b|=frozenset({s+subset})
           return b

If I run the program with:

    print(powerset3(set(['a', 'b'])))

I get following solution

    frozenset({'a', 'b', 'ab'})

But I want to have

    {frozenset(), frozenset({'a'}), frozenset({'b'}), frozenset({'b', 'a'})}

I don't want to use libraries and it should be recursive!

Thanks for your help

Upvotes: 1

Views: 791

Answers (2)

Amit Kumar Gupta
Amit Kumar Gupta

Reputation: 18567

You sort of have the right idea. If a is non-empty, then the powerset of a can be formed by taking some element s from a, and let's called what's left over rest. Then build up the powerset of s from the powerset of rest by adding to it, for each subset in powerset3(rest) both subset itself and subset | frozenset({s}).

That last bit, doing subset | frozenset({s}) instead of string concatenation is half of what's missing with your solution. The other problem is the base case. The powerset of the empty set is not the empty set, is the set of one element containing the empty set.

One more issue with your solution is that you're trying to use frozenset, which is immutable, in mutable ways (e.g. pop(), b |= something, etc.)

Here's a working solution:

from functools import partial

def helper(x, accum, subset):
    return accum | frozenset({subset}) | frozenset({frozenset({x}) | subset})

def powerset(xs):
    if len(xs) == 0:
        return frozenset({frozenset({})})
    else:
        # this loop is the only way to access elements in frozenset, notice
        # it always returns out of the first iteration
        for x in xs:
            return reduce(partial(helper, x), powerset(xs - frozenset({x})), frozenset({}))        

a = frozenset({'a', 'b'})
print(powerset(a))

Upvotes: 0

bakkal
bakkal

Reputation: 55448

Here's a slightly more readable implementation using itertools, if you don't want to use a lib for the combinations, you can replace the combinations code with its implementation e.g. from https://docs.python.org/2/library/itertools.html#itertools.combinations

def powerset(l):
    result = [()]
    for i in range(len(l)):
        result += itertools.combinations(l, i+1)
    return frozenset([frozenset(x) for x in result])

Testing on IPython, with different lengths

In [82]: powerset(['a', 'b'])
Out[82]:
frozenset({frozenset(),
           frozenset({'b'}),
           frozenset({'a'}),
           frozenset({'a', 'b'})})

In [83]: powerset(['x', 'y', 'z'])
Out[83]:
frozenset({frozenset(),
           frozenset({'x'}),
           frozenset({'x', 'z'}),
           frozenset({'y'}),
           frozenset({'x', 'y'}),
           frozenset({'z'}),
           frozenset({'y', 'z'}),
           frozenset({'x', 'y', 'z'})})

In [84]: powerset([])
Out[84]: frozenset({frozenset()})

Upvotes: 1

Related Questions