python - index - Obtener el producto cartesiano de una serie de listas?
python list to string (10)
Aquí hay un generador recursivo, que no almacena ninguna lista temporal
def product(ar_list):
if not ar_list:
yield ()
else:
for a in ar_list[0]:
for prod in product(ar_list[1:]):
yield (a,)+prod
print list(product([[1,2],[3,4],[5,6]]))
Salida:
[(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
¿Cómo puedo obtener el producto cartesiano (cada posible combinación de valores) de un grupo de listas?
Entrada:
somelists = [
[1, 2, 3],
[''a'', ''b''],
[4, 5]
]
Salida deseada:
[(1, ''a'', 4), (1, ''a'', 5), (1, ''b'', 4), (1, ''b'', 5), (2, ''a'', 4), (2, ''a'', 5) ...]
Aunque ya hay muchas respuestas, me gustaría compartir algunos de mis pensamientos:
Enfoque iterativo
def cartesian_iterative(pools):
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
return result
Enfoque Recursivo
def cartesian_recursive(pools):
if len(pools) > 2:
pools[0] = product(pools[0], pools[1])
del pools[1]
return cartesian_recursive(pools)
else:
pools[0] = product(pools[0], pools[1])
del pools[1]
return pools
def product(x, y):
return [xx + [yy] if isinstance(xx, list) else [xx] + [yy] for xx in x for yy in y]
Enfoque Lambda
def cartesian_reduct(pools):
return reduce(lambda x,y: product(x,y) , pools)
En Python 2.6 y superiores puedes usar ''itertools.product`. En versiones anteriores de Python puede usar el siguiente código equivalente (casi, ver documentación) de la documentación , al menos como punto de partida:
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)
El resultado de ambos es un iterador, por lo que si realmente necesita una lista para el procesamiento adicional, utilice la list(result)
.
En Python 2.6+
import itertools
for element in itertools.product(*somelists):
print(element)
Documentación: Python 3 - itertools.product
Para Python 2.5 y mayores:
>>> [(a, b, c) for a in [1,2,3] for b in [''a'',''b''] for c in [4,5]]
[(1, ''a'', 4), (1, ''a'', 5), (1, ''b'', 4), (1, ''b'', 5), (2, ''a'', 4),
(2, ''a'', 5), (2, ''b'', 4), (2, ''b'', 5), (3, ''a'', 4), (3, ''a'', 5),
(3, ''b'', 4), (3, ''b'', 5)]
Aquí hay una versión recursiva del product()
(solo una ilustración):
def product(*args):
if not args:
return iter(((),)) # yield tuple()
return (items + (item,)
for items in product(*args[:-1]) for item in args[-1])
Ejemplo:
>>> list(product([1,2,3], [''a'',''b''], [4,5]))
[(1, ''a'', 4), (1, ''a'', 5), (1, ''b'', 4), (1, ''b'', 5), (2, ''a'', 4),
(2, ''a'', 5), (2, ''b'', 4), (2, ''b'', 5), (3, ''a'', 4), (3, ''a'', 5),
(3, ''b'', 4), (3, ''b'', 5)]
>>> list(product([1,2,3]))
[(1,), (2,), (3,)]
>>> list(product([]))
[]
>>> list(product())
[()]
Solo para agregar un poco a lo que ya se ha dicho: si usas sympy, puedes usar símbolos en lugar de cadenas, lo que los hace matemáticamente útiles.
import itertools
import sympy
x, y = sympy.symbols(''x y'')
somelist = [[x,y], [1,2,3], [4,5]]
somelist2 = [[1,2], [1,2,3], [4,5]]
for element in itertools.product(*somelist):
print element
Acerca de sympy .
Una modificación menor de la solución del generador recursivo anterior en variadic sabor:
def product_args(*args):
if args:
for a in args[0]:
for prod in product_args(*args[1:]) if args[1:] else ((),):
yield (a,) + prod
Y, por supuesto, una envoltura que hace que funcione exactamente igual que esa solución:
def product2(ar_list):
"""
>>> list(product(()))
[()]
>>> list(product2(()))
[]
"""
return product_args(*ar_list)
con una compensación : comprueba si la recursión debería interrumpirse en cada bucle externo, y una ganancia : no hay rendimiento en una llamada vacía, por ejemplo, product(())
, que supongo que sería semánticamente más correcta (consulte el doctest).
Con respecto a la comprensión de la lista: la definición matemática se aplica a un número arbitrario de argumentos, mientras que la comprensión de la lista solo podría tratar con un número conocido de ellos.
Yo usaría la lista de comprensión:
somelists = [
[1, 2, 3],
[''a'', ''b''],
[4, 5]
]
cart_prod = [(a,b,c) for a in somelists[0] for b in somelists[1] for c in somelists[2]]
import itertools
result = list(itertools.product(*somelists))
import itertools
>>> for i in itertools.product([1,2,3],[''a'',''b''],[4,5]):
... print i
...
(1, ''a'', 4)
(1, ''a'', 5)
(1, ''b'', 4)
(1, ''b'', 5)
(2, ''a'', 4)
(2, ''a'', 5)
(2, ''b'', 4)
(2, ''b'', 5)
(3, ''a'', 4)
(3, ''a'', 5)
(3, ''b'', 4)
(3, ''b'', 5)
>>>