Все комбинации списка списков


240

Я в основном ищу Python версию комбинацииList<List<int>>

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

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

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

Ответы:


429

вам нужно 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)]

20
Может ли кто-нибудь объяснить значение звездочки в *a?
Серрано

52
*aозначает, что это аргументы, передаваемые в функцию или метод. def fn(a,b,c):ответил бы на fn(*[1,2,3]) ссылку
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) и т. Д.?
Реман

1
@Reman Не совсем понятно, что вы хотите получить, но если это, например, также обратная сторона каждого кортежа, вы можете использовать функцию-обертку, которая принимает в aкачестве входных данных, выполняет итерацию itertools.product(*a)и выводит как yieldкортеж, созданный, так itertoolsи обратную версию ( например, создать список reverse()и преобразовать его обратно в кортеж). Лучше всего задать новый вопрос.
Иоахим Вагнер

24

Наиболее элегантным решением является использование 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)

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

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


5
Что за точка с запятой? :)
Паоло Бергантино

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


5

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

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']

3

Для этого можно использовать базовый питон. В коде нужна функция для выравнивания списков списков:

def flatten(B):    # function needed for code below;
    A = []
    for i in B:
        if type(i) == list: A.extend(i)
        else: A.append(i)
    return A

Тогда можно запустить:

L = [[1,2,3],[4,5,6],[7,8,9,10]]

outlist =[]; templist =[[]]
for sublist in L:
    outlist = templist; templist = [[]]
    for sitem in sublist:
        for oitem in outlist:
            newitem = [oitem]
            if newitem == [[]]: newitem = [sitem]
            else: newitem = [newitem[0], sitem]
            templist.append(flatten(newitem))

outlist = list(filter(lambda x: len(x)==len(L), templist))  # remove some partial lists that also creep in;
print(outlist)

Вывод:

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

-1
from itertools import product 
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))

Вывод:

[(«Акроним бренда: CBIQ», «Страна бренда: DXB»),
(«Акроним бренда: CBIQ», «Страна бренда: BH»),
(«Акроним бренда: KMEFIC», «Страна бренда: DXB»),
( «Акроним бренда: KMEFIC», «Страна бренда: BH»)]


Этот ответ должен быть принят, поскольку он единственный, использующий встроенную функцию, при этом подчеркивая, что он также работает для любых, а также гетерогенных типов.
pedjjj

Чем этот ответ отличается от ответа, предоставленного много лет назад?
Давид Ласзук
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.