2013-03-07 5 views
2

У меня есть список итерируемых объектов, и я заинтересован в получении всех списков, которые состоят из 0 или 1 элементов из каждого итерабельного (порядок неважен, поэтому это комбинации не перестановок Я ищу).Элегантный способ получения комбинаций для списка итераций

У меня действительно неэффективная реализация, которую я опубликовал ниже.

Я убежден, что есть более элегантный способ сделать это, возможно, с модулем itertools, но я ничего не могу придумать. Любой совет?


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 

Результат:

() 
('A1',) 
('B1',) 
('B2',) 
('B3',) 
('C1',) 
('C2',) 
('A1', 'B1') 
('A1', 'B2') 
('A1', 'B3') 
('A1', 'C1') 
... 
+0

Вам просто интересно отображать результаты или вы также хотите сохранить комбинации? –

+0

@ Edgar, я буду делать что-то еще с результатами, выходящими за рамки этого вопроса, поэтому мне нужно хранить, а не печатать. Визуальное представление - это просто помощь в объяснении моей проблемы! –

ответ

1
[filter(None, comb) for comb in itertools.product(*[[None] + it for it in list_of_iterables])] 

Это делает пару упрощающих предположений. Если ваши итерации содержат значения, которые не соответствуют true в булевом контексте, вам придется использовать более сложный filter. Если ваши итерации не являются списками, вам нужно будет использовать itertools.chain вместо [None] + it.

+0

Мои итерации не являются списками (я использую 'цепочку'), но я реализовал' __nonzero__' для каждого объекта внутри. Это прекрасно работает, спасибо! –

1

Вот что я придумал ...

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 

Выход:

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

Хех, точно так же, как и мой, и мы выложили почти в одно мгновение! Конвергентное мышление! – BrenBarn

+0

Великие умы думают одинаково! – FogleBird

+1

Или это дзен Python? «Должен быть один - и желательно только один - простой способ сделать это». – FogleBird

Смежные вопросы