Como você gera todas as permutações de uma lista no Python, independentemente do tipo de elementos nessa lista?
Por exemplo:
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
fonte
fonte
Respostas:
Começando com Python 2.6 (e se você estiver em Python 3) você tem um padrão da biblioteca ferramenta para isso:
itertools.permutations
.Se você estiver usando um Python mais antigo (<2.6) por algum motivo ou estiver curioso para saber como ele funciona, aqui está uma boa abordagem, feita em http://code.activestate.com/recipes/252178/ :
Algumas abordagens alternativas estão listadas na documentação de
itertools.permutations
. Aqui está um:E outro, baseado em
itertools.product
:fonte
for i in range(len(elements))
vez defor i in range(len(elements)+1)
. De fato, o elemento destacadoelements[0:1]
pode estar emlen(elements)
posições diferentes; no resultado, nãolen(elements)+1
.E no Python 2.6 em diante:
(retornado como um gerador. Use
list(permutations(l))
para retornar como uma lista.)fonte
r
parâmetro, por exemploitertools.permutations([1,2,3], r=2)
, que irá gerar todas as permutações possíveis selecionando 2 elementos:[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
O código a seguir com o Python 2.6 e acima SOMENTE
Primeiro, importe
itertools
:Permutação (ordem importa):
Combinação (a ordem NÃO importa):
Produto cartesiano (com várias iteráveis):
Produto cartesiano (com um iterável e ele próprio):
fonte
chamado como:
fonte
Resultado:
Como estou trocando o conteúdo da lista, é necessário um tipo de sequência mutável como entrada. Por exemplo
perm(list("ball"))
, funcionará eperm("ball")
não funcionará porque você não pode alterar uma string.Essa implementação em Python é inspirada no algoritmo apresentado no livro Computer Algorithms by Horowitz, Sahni and Rajasekeran .
fonte
Esta solução implementa um gerador, para evitar reter todas as permutações na memória:
fonte
Em um estilo funcional
O resultado:
fonte
O código a seguir é uma permutação no local de uma determinada lista, implementada como um gerador. Como ele retorna apenas referências à lista, a lista não deve ser modificada fora do gerador. A solução não é recursiva, portanto, usa pouca memória. Trabalhe bem também com várias cópias de elementos na lista de entrada.
fonte
Uma maneira bastante óbvia na minha opinião pode ser também:
fonte
Resultado:
fonte
Usei um algoritmo baseado no sistema de números fatoriais - Para obter uma lista de comprimento n, você pode montar cada item de permutação por item, selecionando os itens deixados em cada estágio. Você tem n opções para o primeiro item, n-1 para o segundo e apenas uma para o último, para poder usar os dígitos de um número no sistema de números fatoriais como índices. Dessa forma, os números de 0 a n! -1 correspondem a todas as permutações possíveis em ordem lexicográfica.
resultado:
Este método não é recursivo, mas é um pouco mais lento no meu computador e o xrange gera um erro quando n! é muito grande para ser convertido em um inteiro C longo (n = 13 para mim). Foi o suficiente quando eu precisei, mas não há nenhum problema.
fonte
Observe que esse algoritmo tem uma
n factorial
complexidade de tempo, onden
é o comprimento da lista de entradaImprima os resultados na execução:
Exemplo:
Resultado:
fonte
Na verdade, pode-se iterar sobre o primeiro elemento de cada permutação, como na resposta de tzwenn. No entanto, é mais eficiente escrever esta solução desta maneira:
Esta solução é cerca de 30% mais rápida, aparentemente graças à recursão que termina em
len(elements) <= 1
vez de0
. Também é muito mais eficiente em termos de memória, pois utiliza uma função de gerador (atravésyield
), como na solução de Riccardo Reyes.fonte
Isso é inspirado na implementação de Haskell usando a compreensão da lista:
fonte
Implementação regular (sem rendimento - fará tudo na memória):
Implementação de rendimento:
A idéia básica é revisar todos os elementos da matriz para a 1ª posição e, em seguida, na 2ª posição, revisar todos os outros elementos sem o elemento escolhido para a 1ª, etc. Você pode fazer isso com recursão , onde O critério de parada está chegando a uma matriz de 1 elemento - nesse caso, você retorna essa matriz.
fonte
perms = getPermutations(array[:i] + array[i+1:])
numpy
matriz _>getPermutations(np.array([1, 2, 3]))
, vejo que funciona para uma lista, só fiquei confuso como a função arg éarray
:)numba
e ficou ganancioso com velocidade, então tentei usá-lo exclusivamente comnumpy
matrizesPara desempenho, uma solução numpy inspirada em Knuth , (p22):
Copiar grandes blocos de memória economiza tempo - é 20x mais rápido que
list(itertools.permutations(range(n))
:fonte
fonte
Aqui está um algoritmo que funciona em uma lista sem criar novas listas intermediárias semelhantes à solução de Ber em https://stackoverflow.com/a/108651/184528 .
Você pode experimentar o código aqui: http://repl.it/J9v
fonte
A beleza da recursão:
fonte
Este algoritmo é o mais eficaz, evita a passagem e manipulação de array em chamadas recursivas, funciona em Python 2, 3:
Uso:
fonte
fonte
Outra abordagem (sem libs)
A entrada pode ser uma sequência ou uma lista
fonte
[1, 2, 3]
retorna[6, 6, 6, 6, 6, 6]
print(permutation(['1','2','3']))
Isenção de responsabilidade: plugue sem forma por autor do pacote :)
O pacote trotter é diferente da maioria das implementações, pois gera pseudo-listas que na verdade não contêm permutações, mas descreve mapeamentos entre permutações e respectivas posições em uma ordem, tornando possível trabalhar com 'listas' muito grandes de permutações, como mostrado em esta demonstração que executa muito instantânea operações e look-ups em uma pseudo-lista 'contendo' todas as permutações das letras no alfabeto, sem o uso de mais memória ou processamento de uma página web típico.
De qualquer forma, para gerar uma lista de permutações, podemos fazer o seguinte.
Resultado:
fonte
Gere todas as permutações possíveis
Estou usando python3.4:
Casos de teste:
fonte
Para poupar a você horas possíveis de pesquisa e experimentação, aqui está a solução de permutações não recursivas no Python, que também funciona com o Numba (a partir da versão 0.41):
Para dar uma impressão sobre desempenho:
Portanto, use esta versão apenas se você precisar chamá-la da função njitted, caso contrário, prefira a implementação de ferramentas.
fonte
Eu vejo muita iteração acontecendo dentro dessas funções recursivas, não exatamente recursão pura ...
Portanto, para aqueles que não conseguem cumprir nem um único ciclo, aqui está uma solução totalmente recursiva bruta e totalmente desnecessária
fonte
Outra solução:
fonte
Minha solução Python:
fonte
Saída: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']
fonte
Usando
Counter
fonte