Search code examples
pythonpython-itertools

Elegant way to obtain combinations for a list of iterables


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')
...

Solution

  • [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.