ʞɔıu
¿Cómo puedo obtener el producto cartesiano (todas las combinaciones posibles de valores) de un grupo de listas?
Por ejemplo, dado
somelists = [
[1, 2, 3],
['a', 'b'],
[4, 5]
]
¿Cómo consigo esto?
[(1, 'a', 4), (1, 'a', 5), (1, 'b', 4), (1, 'b', 5), (2, 'a', 4), (2, 'a', 5), ...]
Una aplicación común de esta técnica es evitar bucles profundamente anidados. Consulte Evitar bucles for anidados para obtener un duplicado más específico. De manera similar, esta técnica podría usarse para “explotar” un diccionario con valores de lista; consulte Combinar permutaciones de diccionarios de Python en una lista de diccionarios.
Si desea un producto cartesiano de lo mismo lista consigo mismo varias veces, itertools.product
puede manejar eso con elegancia. Ver Operación en cada par de elementos en una lista o ¿Cómo puedo obtener “permutaciones con repeticiones” de una lista (producto cartesiano de una lista consigo misma)?.
Muchas personas que ya conocen itertools.product
lucha con el hecho de que espera argumentos separados para cada secuencia de entrada, en lugar de, por ejemplo, una lista de listas. La respuesta aceptada muestra cómo manejar esto con *
. Sin embargo, el uso de *
aquí para desempaquetar argumentos es fundamentalmente no diferente desde cualquier otro momento en que se use en una llamada de función. Consulte Expansión de tuplas en argumentos para este tema (y utilícelo en su lugar para cerrar preguntas duplicadas, según corresponda).
Bancos de Kenan
Usar itertools.product
que ha estado disponible desde Python 2.6.
import itertools
somelists = [
[1, 2, 3],
['a', 'b'],
[4, 5]
]
for element in itertools.product(*somelists):
print(element)
Esto es lo mismo que:
for element in itertools.product([1, 2, 3], ['a', 'b'], [4, 5]):
print(element)
-
Solo quería agregar el carácter ‘*’ si usa la variable somelists según lo proporcionado por el OP.
– brian dólar
13 de enero de 2011 a las 22:51
-
@jaska:
product()
generanitems_in_a_list ** nlists
elementos en el resultado (reduce(mul, map(len, somelists))
). No hay razón para creer que ceder un solo elemento no esO(nlists)
(amortizado) es decir, la complejidad del tiempo es la misma que para el anidado simplefor
-bucles, por ejemplo, para la entrada en la pregunta:nlists=3
número total de elementos en el resultado:3*2*2
y cada elemento tienenlists
elementos (3
en este caso).– jfs
14 de agosto de 2015 a las 22:08
-
Cuál es el uso de
*
antes de algunas listas? ¿Qué hace?– Vineet Kumar Doshi
25 de agosto de 2015 a las 9:04
-
@VineetKumarDoshi: Aquí se usa para descomponer una lista en múltiples argumentos para la llamada a la función. Lea más aquí: stackoverflow.com/questions/36901/…
– Moberg
15 de septiembre de 2015 a las 6:20
-
Solo un detalle, pero ten en cuenta que
itertools.product()
también puede manejar generadores, y no solo objetos tipo lista.– normanio
5 de diciembre de 2018 a las 23:18
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)
>>>
jfs
Para Python 2.5 y anteriores:
>>> [(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 de 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())
[()]
-
La versión recursiva no funciona si algunos de
args
son iteradores.– jfs
10 de febrero de 2009 a las 21:43
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]]
Fantasma silencioso
con itertools.producto:
import itertools
result = list(itertools.product(*somelists))
-
Cuál es el uso de
*
antes de algunas listas?– Vineet Kumar Doshi
25 de agosto de 2015 a las 9:04
-
@VineetKumarDoshi “producto(algunas listas)” es un producto cartesiano entre las sublistas de manera que Python obtiene primero “[1, 2, 3]” como un elemento y luego obtiene otro elemento después del siguiente comando y ese es el salto de línea, por lo que el primer término del producto es ([1, 2, 3],), similarmente para el segundo ([4, 5],) y entonces “[([1, 2, 3],), ([4, 5],), ([6, 7],)]”. Si desea obtener un producto cartesiano entre elementos dentro de las tuplas, debe informar a Python con Asterisk sobre la estructura de la tupla. Para el diccionario, usa **. Más aquí.
– hhh
15 de febrero de 2016 a las 23:13
Anurag Uniyal
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]]))
Producción:
[(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
-
Cuál es el uso de
*
antes de algunas listas?– Vineet Kumar Doshi
25 de agosto de 2015 a las 9:04
-
@VineetKumarDoshi “producto(algunas listas)” es un producto cartesiano entre las sublistas de manera que Python obtiene primero “[1, 2, 3]” como un elemento y luego obtiene otro elemento después del siguiente comando y ese es el salto de línea, por lo que el primer término del producto es ([1, 2, 3],), similarmente para el segundo ([4, 5],) y entonces “[([1, 2, 3],), ([4, 5],), ([6, 7],)]”. Si desea obtener un producto cartesiano entre elementos dentro de las tuplas, debe informar a Python con Asterisk sobre la estructura de la tupla. Para el diccionario, usa **. Más aquí.
– hhh
15 de febrero de 2016 a las 23:13
En Python 2.6 y superior, puede usar ‘itertools.product`. En versiones anteriores de Python, puede usar el siguiente equivalente (casi, consulte la documentación) código de la documentaciónal 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 un procesamiento posterior, use list(result)
.
-
Según la documentación, la implementación real de itertools.product NO genera resultados intermedios, lo que podría ser costoso. El uso de esta técnica podría salirse de control con bastante rapidez para las listas de tamaño moderado.
– Kenan Banks
10 de febrero de 2009 a las 20:05
-
Solo puedo señalar el OP a la documentación, no leerlo por él.
– usuario3850
10 de febrero de 2009 a las 20:19
-
El código de la documentación está destinado a demostrar lo que hace la función del producto, no como una solución para versiones anteriores de Python.
– Kenan Banks
10 de marzo de 2009 a las 21:07
tenga en cuenta que ‘todas las combinaciones posibles’ no es lo mismo que ‘producto cartesiano’, ya que en los productos cartesianos se permiten duplicados.
– Kenan Banks
10 de febrero de 2009 a las 20:08
¿Existe una versión no duplicada del producto cartesiano?
– KJW
13 de noviembre de 2013 a las 5:32
@KJW Sí,
set(cartesian product)
– Sin errores
12 de febrero de 2015 a las 7:04
No debe haber duplicados en un producto cartesiano, a menos que las listas de entrada contengan duplicados. Si no desea duplicados en el producto cartesiano, utilice
set(inputlist)
sobre todas sus listas de entrada. No en el resultado.– CamilB
24 de agosto de 2017 a las 8:39
Matemáticamente, un producto cartesiano es un conjunto, por lo que un producto cartesiano no no contienen duplicados. Por otro lado,
itertools.product
tendrá duplicados en la salida si las entradas tienen duplicados. Entoncesitertools.product
no es estrictamente hablando el producto cartesiano, a menos que envuelva las entradas enset
como lo menciona @CamilB.–Cameron Bieganek
8 dic 2020 a las 22:56