2009-04-28 7 views
137

Я в основном ищет версию питона из Combination of List<List<int>>Все комбинации списка списков

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

[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]] 

Количество списков неизвестно, поэтому мне нужно что-то, что работает для всех случаев. Бонусные очки за элегантность!

ответ

266

вам нужно itertools.product:

>>> import itertools 
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]] 
>>> list(itertools.product(*a)) 
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)] 
+10

Мог кто-то объясняет значение звездочки в '* a'? – Serrano

+23

'* a' означает, что это аргументы, передаваемые функции или методу. 'def fn (a, b, c):' будет отвечать на 'fn (* [1,2,3])' [reference] (http://www.saltycrane.com/blog/2008/01/how- to-use-args-and-kwargs-in-python /) – mjallday

+1

@mjallday, можно было бы также добавить эти комбинации: (7,4,1), (8,4,1), (9,4, 1), (10,4,1), (7,5,1), (8,5,1), (9,5,1), (10,5,1) и т. Д.? – Reman

23

Самое элегантное решение заключается в использовании itertools.product в Python 2.6.

Если вы не используете Python 2.6, то документы для itertools.product фактически показывают эквивалентную функцию, чтобы сделать продукт «ручной» способ:

def product(*args, **kwds): 
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy 
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 
    pools = map(tuple, args) * kwds.get('repeat', 1) 
    result = [[]] 
    for pool in pools: 
     result = [x+[y] for x in result for y in pool] 
    for prod in result: 
     yield tuple(prod) 
+0

Теперь я использую 2.6, но спасибо за информацию! – Lin

14
listOLists = [[1,2,3],[4,5,6],[7,8,9,10]] 
for list in itertools.product(*listOLists): 
    print list; 

Я надеюсь, что вы найдете, что, как элегантный, как я, когда я впервые столкнулся с этим.

+2

Что случилось с этой точкой с запятой? :) –

+3

Сила привычки. Мне нравится, как Python позволяет вам помещать одну двоеточие, чтобы помочь нам программистам C/Java. Но это понятно; на самом деле не является терминатором утверждения, когда вы делаете что-то вроде print («foo») ;; который совершенно легален на C или Java (хотя и бессмыслен), но запрещен в Python. –

2

Numpy может это сделать:

>>> import numpy 
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]] 
>>> [list(x) for x in numpy.array(numpy.meshgrid(*a)).T.reshape(-1,len(a))] 
[[ 1, 4, 7], [1, 5, 7], [1, 6, 7], ....] 
+0

Может ли кто-нибудь объяснить это? – ashishv

0

Ничего плохого с прямой до рекурсии для выполнения этой задачи, и если вам нужна версия, которая работает со строками, это могло бы соответствовать вашим потребностям:

combinations = [] 

def combine(terms, accum): 
    last = (len(terms) == 1) 
    n = len(terms[0]) 
    for i in range(n): 
     item = accum + terms[0][i] 
     if last: 
      combinations.append(item) 
     else: 
      combine(terms[1:], item) 


>>> a = [['ab','cd','ef'],['12','34','56']] 
>>> combine(a, '') 
>>> print(combinations) 
['ab12', 'ab34', 'ab56', 'cd12', 'cd34', 'cd56', 'ef12', 'ef34', 'ef56']