2

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')
...
2
  • Are you simply interested in displaying the results or do you also want the combinations stored? Commented Mar 7, 2013 at 20:57
  • @Edgar, I'll be doing something else with the results that is out of the scope of this question, so I need to store, not print. The visual representation is just to aid the explanation of my problem! Commented Mar 7, 2013 at 21:04

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

1 Comment

My iterables are not lists (Ill use chain), but I have implemented __nonzero__` on each object within. This works wonderfully, thank you!
1

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

2 Comments

Heh, exactly the same as mine, and we posted at almost the same instant! Convergent thinking!
Or is it the zen of Python? "There should be one-- and preferably only one --obvious way to do it."

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.