¿Cómo se generan todas las permutaciones de una lista en Python, independientemente del tipo de elementos en esa lista?
Por ejemplo:
permutations([])
[]
permutations([1])
[1]
permutations([1, 2])
[1, 2]
[2, 1]
permutations([1, 2, 3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
python
algorithm
permutation
combinatorics
python-2.5
Ricardo Reyes
fuente
fuente
Respuestas:
A partir de Python 2.6 (y si estás en Python 3) tiene una norma-biblioteca herramienta para esto:
itertools.permutations
.Si está utilizando un Python anterior (<2.6) por alguna razón o simplemente tiene curiosidad por saber cómo funciona, aquí hay un buen enfoque, tomado de http://code.activestate.com/recipes/252178/ :
Un par de enfoques alternativos se enumeran en la documentación de
itertools.permutations
. Aquí hay uno:Y otro, basado en
itertools.product
:fuente
for i in range(len(elements))
lugar defor i in range(len(elements)+1)
. De hecho, el elemento seleccionadoelements[0:1]
puede estar enlen(elements)
diferentes posiciones, en el resultado, nolen(elements)+1
.Y en Python 2.6 en adelante:
(devuelto como generador. Utilícelo
list(permutations(l))
para regresar como una lista).fuente
r
parámetro, por ejemploitertools.permutations([1,2,3], r=2)
, que generará todas las permutaciones posibles seleccionando 2 elementos:[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
El siguiente código con Python 2.6 y superior SOLAMENTE
Primero, importa
itertools
:Permutación (el orden importa):
Combinación (el orden NO importa):
Producto cartesiano (con varios iterables):
Producto cartesiano (con uno iterable y en sí mismo):
fuente
llamado:
fuente
Salida:
Como estoy intercambiando el contenido de la lista, se requiere un tipo de secuencia mutable como entrada. Por ejemplo
perm(list("ball"))
, funcionará yperm("ball")
no lo hará porque no puede cambiar una cadena.Esta implementación de Python está inspirada en el algoritmo presentado en el libro Algoritmos informáticos de Horowitz, Sahni y Rajasekeran .
fuente
Esta solución implementa un generador, para evitar mantener todas las permutaciones en la memoria:
fuente
En un estilo funcional
El resultado:
fuente
El siguiente código es una permutación in situ de una lista dada, implementada como un generador. Como solo devuelve referencias a la lista, la lista no debe modificarse fuera del generador. La solución no es recursiva, por lo que utiliza poca memoria. Funciona bien también con múltiples copias de elementos en la lista de entrada.
fuente
Una forma bastante obvia en mi opinión podría ser también:
fuente
Salida:
fuente
Utilicé un algoritmo basado en el sistema de números factoriales : para una lista de longitud n, puede ensamblar cada elemento de permutación por elemento, seleccionando entre los elementos que quedan en cada etapa. Tiene n opciones para el primer elemento, n-1 para el segundo y solo una para el último, por lo que puede usar los dígitos de un número en el sistema de números factoriales como índices. De esta manera, los números del 0 al n! -1 corresponden a todas las permutaciones posibles en orden lexicográfico.
salida:
Este método no es recursivo, pero es un poco más lento en mi computadora y xrange genera un error cuando n! es demasiado grande para convertirlo en un entero C largo (n = 13 para mí). Fue suficiente cuando lo necesitaba, pero no es itertools.permutations por asomo.
fuente
Tenga en cuenta que este algoritmo tiene una
n factorial
complejidad temporal, donden
es la longitud de la lista de entradaImprima los resultados en la ejecución:
Ejemplo:
Salida:
fuente
De hecho, uno puede iterar sobre el primer elemento de cada permutación, como en la respuesta de tzwenn. Sin embargo, es más eficiente escribir esta solución de esta manera:
Esta solución es aproximadamente un 30% más rápida, aparentemente gracias a que la recursión termina en
len(elements) <= 1
lugar de0
. También es mucho más eficiente en la memoria, ya que utiliza una función de generador (a travésyield
), como en la solución de Riccardo Reyes.fuente
Esto está inspirado en la implementación de Haskell utilizando la comprensión de la lista:
fuente
Implementación regular (sin rendimiento; hará todo en la memoria):
Implementación de rendimiento:
La idea básica es repasar todos los elementos de la matriz para la primera posición, y luego, en la segunda posición, repasar el resto de los elementos sin el elemento elegido para la primera, etc. Puede hacerlo con recursividad , donde el criterio de detención es llegar a una matriz de 1 elemento, en cuyo caso devuelve esa matriz.
fuente
perms = getPermutations(array[:i] + array[i+1:])
numpy
matriz _>getPermutations(np.array([1, 2, 3]))
, veo que funciona para una lista, me confundí porque el argumento esarray
:)numba
y se volvió codicioso con la velocidad, así que traté de usarlo exclusivamente connumpy
matricesPara el rendimiento, una solución complicada inspirada en Knuth , (p22):
Copiar grandes bloques de memoria ahorra tiempo: es 20 veces más rápido que
list(itertools.permutations(range(n))
:fuente
fuente
Aquí hay un algoritmo que funciona en una lista sin crear nuevas listas intermedias similares a la solución de Ber en https://stackoverflow.com/a/108651/184528 .
Puede probar el código usted mismo aquí: http://repl.it/J9v
fuente
La belleza de la recursividad:
fuente
Este algoritmo es el más efectivo, evita el paso de matriz y la manipulación en llamadas recursivas, funciona en Python 2, 3:
Uso:
fuente
fuente
OTRO ENFOQUE (sin libs)
La entrada puede ser una cadena o una lista
fuente
[1, 2, 3]
vuelve[6, 6, 6, 6, 6, 6]
print(permutation(['1','2','3']))
Descargo de responsabilidad: enchufe sin forma por autor del paquete. :)
El paquete trotter es diferente de la mayoría de las implementaciones en el sentido de que genera pseudo listas que en realidad no contienen permutaciones, sino que describen asignaciones entre permutaciones y posiciones respectivas en un orden, lo que permite trabajar con 'listas' muy grandes de permutaciones, como se muestra en esta demo que realiza operaciones y búsquedas bastante instantáneas en una pseudo-lista que 'contiene' todas las permutaciones de las letras en el alfabeto, sin usar más memoria o procesamiento que una página web típica.
En cualquier caso, para generar una lista de permutaciones, podemos hacer lo siguiente.
Salida:
fuente
Generar todas las permutaciones posibles.
Estoy usando python3.4:
Casos de prueba:
fuente
Para ahorrarles a las personas posibles horas de búsqueda y experimentación, aquí está la solución de permutaciones no recursiva en Python que también funciona con Numba (a partir del v. 0.41):
Para dar una impresión sobre el rendimiento:
Por lo tanto, use esta versión solo si debe llamarla desde la función njitted, de lo contrario, prefiera la implementación de itertools.
fuente
Veo mucha iteración dentro de estas funciones recursivas, no exactamente pura recursión ...
así que para aquellos de ustedes que no pueden cumplir ni siquiera un solo bucle, aquí hay una solución grosera, totalmente innecesaria y totalmente recursiva
fuente
Otra solución:
fuente
Mi solución Python:
fuente
Salida: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
fuente
Utilizando
Counter
fuente