¿Cómo puedo obtener “permutaciones con repeticiones/reemplazos” de una lista (producto cartesiano de una lista consigo misma)?

4 minutos de lectura

Avatar de usuario de Bwmat
bwmat

Supongamos que tengo una lista die_faces = [1, 2, 3, 4, 5, 6]. Quiero generar los 36 resultados posibles para lanzar dos dados: (1, 1), (1, 2), (2, 1) etc. Si trato de usar permutations desde el itertools biblioteca estándar:

>>> import itertools
>>> die_faces = [1, 2, 3, 4, 5, 6]
>>> list(itertools.permutations(die_faces, 2))
[(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 3), (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 4), (3, 5), (3, 6), (4, 1), (4, 2), (4, 3), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), (5, 4), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5)]

solo hay 30 resultados, faltando aquellos en los que sale el mismo número en ambos dados. Parece que solo genera permutaciones sin repeticiones. ¿Cómo puedo arreglar esto?

  • Consulte también stackoverflow.com/questions/942543 para el caso de llamar directamente a una función con los nuevos valores.

    – Karl Knechtel

    3 de julio de 2022 a las 16:30

avatar de usuario de miku
miku

estas buscando el Producto cartesiano.

En matemáticas, un producto cartesiano (o conjunto de productos) es el producto directo de dos conjuntos.

En tu caso, esto sería {1, 2, 3, 4, 5, 6} X {1, 2, 3, 4, 5, 6}.
itertools te puede ayudar ahi:

import itertools
x = [1, 2, 3, 4, 5, 6]
[p for p in itertools.product(x, repeat=2)]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 3), 
 (2, 4), (2, 5), (2, 6), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), 
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (5, 1), (5, 2), (5, 3), 
 (5, 4), (5, 5), (5, 6), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6)]

Para obtener una tirada de dados al azar (en un manera totalmente ineficiente):

import random
random.choice([p for p in itertools.product(x, repeat=2)])
(6, 3)

  • Esta es una forma extremadamente ineficiente de obtener 2 tiradas de dados… Dos llamadas a random.randint sería más simple y eficiente.

    – Eric O Lebigot

    23 de junio de 2010 a las 9:39

  • Las tiradas aleatorias de dados serán mucho más rápidas cuando no generes todos los pares posibles: [random.randint(1,6) for i in xrange(2)]

    – liori

    23 de junio de 2010 a las 9:42

  • En realidad, no estaba tratando de generar tiradas aleatorias, solo para enumerar todas las tiradas posibles.

    – Bwmat

    23 de junio de 2010 a las 10:18

Avatar de usuario de Mark Byers
marca byers

No está buscando permutaciones, quiere la Producto cartesiano. Para este uso producto de itertools:

from itertools import product
for roll in product([1, 2, 3, 4, 5, 6], repeat = 2):
    print(roll)

En python 2.7 y 3.1 hay un itertools.combinations_with_replacement función:

>>> list(itertools.combinations_with_replacement([1, 2, 3, 4, 5, 6], 2))
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4), 
 (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 4), (4, 5), (4, 6),
 (5, 5), (5, 6), (6, 6)]

  • Esta solución pierde en las combinaciones (2, 1), (3, 2), (3, 1) y similares… En general omite todas las combinaciones donde el segundo rollo es más bajo que el primero.

    – Holroy

    16 de noviembre de 2015 a las 18:48


  • ¡Tal vez no sea la solución “correcta”, sino la correcta para mí! ¡Gracias!

    – jbm

    21 oct 2021 a las 0:16

  • tengo que votar negativamente ya que @holroy tiene razón y esto puede ser confuso

    – shabunc

    21 de abril de 2022 a las 10:35

avatar de usuario de pylang
pilang

En este caso, una lista de comprensión no es particularmente necesaria.

Dado

import itertools as it


seq = range(1, 7)
r = 2

Código

list(it.product(seq, repeat=r))

Detalles

Obviamente, el producto cartesiano puede generar subconjuntos de permutaciones. Sin embargo, se sigue que:

  • con reemplazo: producir todas las permutaciones nr a través de product
  • sin reemplazo: filtro de este último

Permutaciones con reemplazo, nr

[x for x in it.product(seq, repeat=r)]

Permutaciones sin reemplazo, n!

[x for x in it.product(seq, repeat=r) if len(set(x)) == r]
# Equivalent
list(it.permutations(seq, r))  

En consecuencia, todas las funciones combinatorias podrían implementarse a partir de product:

Avatar de usuario de Euler_Salter
Euler_Salter

Creo que encontré una solución usando solo lambdas, map y reduce.

product_function = lambda n: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(n)), [])

Esencialmente, estoy mapeando una primera función lambda que, dada una fila, itera las columnas

list(map(lambda j: (i, j), np.arange(n)))

entonces esto se usa como salida de una nueva función lambda

lambda i:list(map(lambda j: (i, j), np.arange(n)))

que se asigna a través de todas las filas posibles

map(lambda i: list(map(lambda j: (i, j), np.arange(n))), np.arange(m))

y luego reducimos todas las listas resultantes en una sola.

aun mejor

También puede utilizar dos números diferentes.

prod= lambda n, m: reduce(lambda x, y: x+y, map(lambda i: list(map(lambda j: (i, j), np.arange(m))), np.arange(n)), [])

Avatar de usuario de Eric_HL_DoCode
Eric_HL_DoCode

Primero, primero querrá convertir el generador devuelto por itertools.permutations(list) en una lista. Luego, en segundo lugar, puede usar set () para eliminar duplicados Algo como a continuación:

def permutate(a_list):
    import itertools
    return set(list(itertools.permutations(a_list)))

¿Ha sido útil esta solución?