Given a set
{0, 1, 2, 3}
How can I produce the subsets:
[set(),
{0},
{1},
{2},
{3},
{0, 1},
{0, 2},
{0, 3},
{1, 2}
def powerset(lst):
return reduce(lambda result, x: result + [subset + [x] for subset in result],
lst, [[]])
There is a refinement of powerset:
def powerset(seq):
"""
Returns all the subsets of this set. This is a generator.
"""
if len(seq) <= 0:
yield []
else:
for item in powerset(seq[1:]):
yield [seq[0]]+item
yield item
def get_power_set(s):
power_set=[[]]
for elem in s:
# iterate over the sub sets so far
for sub_set in power_set:
# add a new subset consisting of the subset at hand added elem
power_set=power_set+[list(sub_set)+[elem]]
return power_set
For example:
get_power_set([1,2,3])
yield
[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
The Python itertools page has exactly a powerset
recipe for this:
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
Output:
>>> list(powerset("abcd"))
[(), ('a',), ('b',), ('c',), ('d',), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd'), ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd'), ('a', 'b', 'c', 'd')]
If you don't like that empty tuple at the beginning, you can just change the range
statement to range(1, len(s)+1)
to avoid a 0-length combination.
Just a quick power set refresher !
Power set of a set X, is simply the set of all subsets of X including the empty set
Example set X = (a,b,c)
Power Set = { { a , b , c } , { a , b } , { a , c } , { b , c } , { a } , { b } , { c } , { } }
Here is another way of finding power set:
def power_set(input):
# returns a list of all subsets of the list a
if (len(input) == 0):
return [[]]
else:
main_subset = [ ]
for small_subset in power_set(input[1:]):
main_subset += [small_subset]
main_subset += [[input[0]] + small_subset]
return main_subset
print(power_set([0,1,2,3]))
full credit to source
Almost all of these answers use list
rather than set
, which felt like a bit of a cheat to me. So, out of curiosity I tried to do a simple version truly on set
and summarize for other "new to Python" folks.
I found there's a couple oddities in dealing with Python's set implementation. The main surprise to me was handling empty sets. This is in contrast to Ruby's Set implementation, where I can simply do Set[Set[]]
and get a Set
containing one empty Set
, so I found it initially a little confusing.
To review, in doing powerset
with set
s, I encountered two problems:
set()
takes an iterable, so set(set())
will return set()
because the empty set iterable is empty (duh I guess :))set({set()})
and set.add(set)
won't work because set()
isn't hashableTo solve both issues, I made use of frozenset()
, which means I don't quite get what I want (type is literally set
), but makes use of the overall set
interace.
def powerset(original_set):
# below gives us a set with one empty set in it
ps = set({frozenset()})
for member in original_set:
subset = set()
for m in ps:
# to be added into subset, needs to be
# frozenset.union(set) so it's hashable
subset.add(m.union(set([member]))
ps = ps.union(subset)
return ps
Below we get 2² (16) frozenset
s correctly as output:
In [1]: powerset(set([1,2,3,4]))
Out[2]:
{frozenset(),
frozenset({3, 4}),
frozenset({2}),
frozenset({1, 4}),
frozenset({3}),
frozenset({2, 3}),
frozenset({2, 3, 4}),
frozenset({1, 2}),
frozenset({2, 4}),
frozenset({1}),
frozenset({1, 2, 4}),
frozenset({1, 3}),
frozenset({1, 2, 3}),
frozenset({4}),
frozenset({1, 3, 4}),
frozenset({1, 2, 3, 4})}
As there's no way to have a set
of set
s in Python, if you want to turn these frozenset
s into set
s, you'll have to map them back into a list
(list(map(set, powerset(set([1,2,3,4]))))
) or modify the above.