Todas las combinaciones de una lista de listas.


240

Básicamente estoy buscando una versión python de Combination ofList<List<int>>

Dada una lista de listas, necesito una nueva lista que proporcione todas las combinaciones posibles de elementos entre las listas.

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

El número de listas es desconocido, por lo que necesito algo que funcione para todos los casos. ¡Puntos de bonificación por elegancia!

Respuestas:


429

necesitas 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
¿Alguien podría explicar el significado del asterisco en *a?
Serrano

52
*asignifica que estos son argumentos que se pasan a la función o método. def fn(a,b,c):respondería a la fn(*[1,2,3]) referencia
mjallday

1
@mjallday, ¿sería posible agregar también estas combinaciones: (7,4,1), (8,4,1), (9,4,1), (10,4,1), (7,5, 1), (8,5,1), (9,5,1), (10,5,1) etc.
Reman

1
@Reman No está del todo claro lo que desea obtener, pero si es, por ejemplo, también el reverso de cada tupla, puede usar una función de contenedor que tome acomo entrada, itere itertools.product(*a)y yields la tupla producida por itertoolsy una versión inversa ( Por ejemplo, crear una lista reverse()y convertirla de nuevo en tupla). Mejor hacer una nueva pregunta.
Joachim Wagner

24

La solución más elegante es usar itertools.product en python 2.6.

Si no está utilizando Python 2.6, los documentos para itertools.product en realidad muestran una función equivalente para hacer el producto de forma "manual":

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;

Espero que lo encuentres tan elegante como yo cuando lo encontré por primera vez.


55
¿Qué pasa con ese punto y coma? :)
Paolo Bergantino

3
Fuerza de la costumbre. Me encanta cómo Python te permite poner un punto y coma, solo para ayudarnos a los viejos programadores de C / Java. Pero está claro; no es realmente un terminador de declaraciones cuando haces algo como imprimir ("foo") ;; que es perfectamente legal en C o Java (aunque no tiene sentido) pero está prohibido en Python.
Matthew Flaschen

5

Numpy puede hacerlo:

 >>> 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], ....]

¿Alguien podría explicar esto?
ashishv

5

No hay nada malo en la recursividad directa para esta tarea, y si necesita una versión que funcione con cadenas, esto podría satisfacer sus necesidades:

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

Uno puede usar Python base para esto. El código necesita una función para aplanar listas de listas:

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

Entonces uno puede ejecutar:

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)

Salida:

[[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))

Salida:

[('Acrónimo de marca: CBIQ', 'País de marca: DXB'),
('Acrónimo de marca: CBIQ', 'País de marca: BH'),
('Acrónimo de marca: KMEFIC', 'País de marca: DXB'),
( 'Acrónimo de marca: KMEFIC', 'País de marca: BH')]


Esta respuesta debe aceptarse, ya que es la única que utiliza una función incorporada, al tiempo que destaca que también funciona para cualquier tipo y también para tipos heterogéneos.
pedjjj

¿En qué se diferencia esta respuesta de la que se proporcionó hace muchos años?
Dawid Laszuk
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.