How to get all subsets of a set? (powerset)
Here is more code for a powerset. This is written from scratch:
>>> def powerset(s):
... x = len(s)
... for i in range(1 << x):
... print [s[j] for j in range(x) if (i & (1 << j))]
...
>>> powerset([4,5,6])
[]
[4]
[5]
[4, 5]
[6]
[4, 6]
[5, 6]
[4, 5, 6]
Mark Rushakoff's comment is applicable here: "If you don't like that empty tuple at the beginning, on."you can just change the range statement to range(1, len(s)+1) to avoid a 0-length combination", except in my case you change for i in range(1 << x)
to for i in range(1, 1 << x)
.
Returning to this years later, I'd now write it like this:
def powerset(s):
x = len(s)
masks = [1 << i for i in range(x)]
for i in range(1 << x):
yield [ss for mask, ss in zip(masks, s) if i & mask]
And then the test code would look like this, say:
print(list(powerset([4, 5, 6])))
Using yield
means that you do not need to calculate all results in a single piece of memory. Precalculating the masks outside the main loop is assumed to be a worthwhile optimization.
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.