David Cain
David Cain

Reputation: 17353

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

Upvotes: 2

Views: 290

Answers (2)

BrenBarn
BrenBarn

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

FogleBird
FogleBird

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

Related Questions