简体   繁体   中英

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

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 eg 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()})

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}) subset | frozenset({s}) .

That last bit, doing subset | frozenset({s}) 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 (eg 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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM