Reputation: 17353
I have a list of iterable objects, and I'm interested in obtaining all lists that consist of 0 or 1 items from each iterable (order is unimportant, so it's combinations not permutations I seek).
I have a really inelegant implementation that I've posted below.
I'm convinced there's a far more elegant way to do this, possibly with the itertools
module, but I can't come up with anything. Any advice?
import itertools
def all_subsets(ss):
subset_lens = range(0, len(ss) + 1)
list_of_subsets = map(lambda n: itertools.combinations(ss, n), subset_lens)
return itertools.chain.from_iterable(list_of_subsets)
list_of_iterables = [["A1"], ["B1", "B2", "B3"], ["C1", "C2"]]
all_possibilities = itertools.chain.from_iterable(itertools.product(*subset)
for subset in all_subsets(list_of_iterables))
# Visual representation of the desired result
for eg in all_possibilities:
print eg
Result:
()
('A1',)
('B1',)
('B2',)
('B3',)
('C1',)
('C2',)
('A1', 'B1')
('A1', 'B2')
('A1', 'B3')
('A1', 'C1')
...
Upvotes: 2
Views: 290
Reputation: 251568
[filter(None, comb) for comb in itertools.product(*[[None] + it for it in list_of_iterables])]
This makes a couple simplifying assumptions. If your iterables contain values that aren't true in a boolean context, you'd have to use a more complicated filter
. If your iterables aren't lists, you'd have to use itertools.chain
instead of [None] + it
.
Upvotes: 1
Reputation: 76842
Here's what I came up with...
data = [["A1"], ["B1", "B2", "B3"], ["C1", "C2"]]
data = [[None] + x for x in data]
data = sorted(filter(None, x) for x in itertools.product(*data))
for result in data:
print result
Output:
()
('A1',)
('A1', 'B1')
('A1', 'B1', 'C1')
('A1', 'B1', 'C2')
('A1', 'B2')
('A1', 'B2', 'C1')
('A1', 'B2', 'C2')
('A1', 'B3')
('A1', 'B3', 'C1')
('A1', 'B3', 'C2')
('A1', 'C1')
('A1', 'C2')
('B1',)
('B1', 'C1')
('B1', 'C2')
('B2',)
('B2', 'C1')
('B2', 'C2')
('B3',)
('B3', 'C1')
('B3', 'C2')
('C1',)
('C2',)
Upvotes: 1