Sin embargo, tendrás que unir tus letras permutadas como cadenas.
['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 'sactk', 'sackt', 'saktc', 'sakct', ' sctak ',' sctka ',' scatk ',' scakt ',' sckta ',' sckat ',' sktac ',' sktca ',' skatc ',' skact ',' skcta ',' skcat ',' tsack ' , 'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 'taksc', 'takcs', 'tcsak', ' tcska ',' tcask ',' tcaks ',' tcksa ',' tckas ',' tksac ',' tksca ',' tkasc ',' tkacs ',' tkcsa ',' tkcas ',' astck ','astkc ',' asctk ',' asckt ',' asktc ',' askct ',' atsck ',' atskc ',' atcsk ',' atcks ',' atksc ',' atkcs ',' acstk ',' acskt ' , 'actks', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 'akcst', 'akcts', 'cstak', 'cstka', ' csatk ',' csakt ',' cskta ',' cskat ',' ctsak ',' ctska ',' ctask ',' ctaks ',' ctksa ',' ctkas ',' castk ',' caskt ',' catsk ' , 'catks', 'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 'kstca', 'ksatc','ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs ',' kacst ',' kacts ',' kcsta ',' kcsat ',' kctsa ',' kctas ',' kcast ',' kcats ']
Si tiene problemas con los duplicados, intente ajustar sus datos en una estructura sin duplicados como set
:
Gracias a @pst por señalar que esto no es lo que tradicionalmente pensaríamos como una conversión de tipos, sino más bien una llamada al set()
constructor.
set(...)
no "lanza". Más bien, genera (y produce) el conjunto que representa la colección de entrada: una vez generado, no tiene asociación con la colección de entrada (y es un objeto diferente, no solo una vista diferente).bool
, es una función que se evalúa como bool (Verdadero / Falso) dependiendo de la entrada. Encuentro que el uso de "emitir" aquí es falso y engañoso ...¡Puedes conseguir todo N! permutaciones sin mucho código
def permutations(string, step = 0): # if we've gotten to the end, print the permutation if step == len(string): print "".join(string) # everything to the right of step has not been swapped yet for i in range(step, len(string)): # copy the string (store as array) string_copy = [character for character in string] # swap the current index with the step string_copy[step], string_copy[i] = string_copy[i], string_copy[step] # recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1) permutations(string_copy, step + 1)
fuente
step == len(string)
lugar destep == len(string) - 1
?Aquí hay otra forma de hacer la permutación de cadena con código mínimo. Básicamente creamos un bucle y luego seguimos intercambiando dos caracteres a la vez. Dentro del bucle tendremos la recursividad. Observe que solo imprimimos cuando los indexadores alcanzan la longitud de nuestra cadena. Ejemplo: ABC i para nuestro punto de partida y nuestro parámetro de recursividad j para nuestro bucle
aquí hay una ayuda visual sobre cómo funciona de izquierda a derecha de arriba a abajo (es el orden de permutación)
el código :
def permute(data, i, length): if i==length: print(''.join(data) ) else: for j in range(i,length): #swap data[i], data[j] = data[j], data[i] permute(data, i+1, length) data[i], data[j] = data[j], data[i] string = "ABC" n = len(string) data = list(string) permute(data, 0, n)
fuente
Los usuarios de Stack Overflow ya han publicado algunas soluciones sólidas, pero quería mostrar otra solución. Este me parece más intuitivo
La idea es que para una cadena dada: podemos recurrir mediante el algoritmo (pseudocódigo):
¡Espero que esto ayude a alguien!
def permutations(string): """ Create all permutations of a string with non-repeating characters """ permutation_list = [] if len(string) == 1: return [string] else: for char in string: [permutation_list.append(char + a) for a in permutations(string.replace(char, "", 1))] return permutation_list
fuente
Aquí hay una función simple para devolver permutaciones únicas:
def permutations(string): if len(string) == 1: return string recursive_perms = [] for c in string: for perm in permutations(string.replace(c,'',1)): revursive_perms.append(c+perm) return set(revursive_perms)
fuente
revursive_perms
->recursive_perms
. 2. Ahorraría RAM y tiempo sirecursive_perms
fuera un conjunto en lugar de una lista que se convierte en un conjunto en la declaración de retorno. 3. Sería más eficiente usar la división de cadenas en lugar de.replace
construir el argumento para la llamada recursiva depermutations
. 4. No es una buena idea utilizarlostring
como nombre de variable porque oculta el nombre delstring
módulo estándar .Aquí hay otro enfoque diferente al que publicaron @Adriano y @illerucis. Esto tiene un mejor tiempo de ejecución, puede verificarlo usted mismo midiendo el tiempo:
def removeCharFromStr(str, index): endIndex = index if index == len(str) else index + 1 return str[:index] + str[endIndex:] # 'ab' -> a + 'b', b + 'a' # 'abc' -> a + bc, b + ac, c + ab # a + cb, b + ca, c + ba def perm(str): if len(str) <= 1: return {str} permSet = set() for i, c in enumerate(str): newStr = removeCharFromStr(str, i) retSet = perm(newStr) for elem in retSet: permSet.add(c + elem) return permSet
Para una cadena arbitraria "dadffddxcf", tomó 1,1336 segundos para la biblioteca de permutación, 9,125 segundos para esta implementación y 16,357 segundos para la versión de @ Adriano y @illerucis. Por supuesto, aún puede optimizarlo.
fuente
itertools.permutations
es bueno, pero no funciona bien con secuencias que contienen elementos repetidos. Eso es porque internamente permuta los índices de secuencia y no tiene en cuenta los valores de los elementos de la secuencia.Claro, es posible filtrar la salida de a
itertools.permutations
través de un conjunto para eliminar los duplicados, pero aún así se pierde tiempo generando esos duplicados, y si hay varios elementos repetidos en la secuencia base, habrá muchos duplicados. Además, usar una colección para almacenar los resultados desperdicia RAM, anulando el beneficio de usar un iterador en primer lugar.Afortunadamente, existen enfoques más eficientes. El siguiente código utiliza el algoritmo del matemático indio del siglo XIV Narayana Pandita, que se puede encontrar en el artículo de Wikipedia sobre Permutación . Este antiguo algoritmo sigue siendo una de las formas más rápidas conocidas de generar permutaciones en orden, y es bastante robusto, ya que maneja correctamente las permutaciones que contienen elementos repetidos.
def lexico_permute_string(s): ''' Generate all permutations in lexicographic order of string `s` This algorithm, due to Narayana Pandita, is from https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order To produce the next permutation in lexicographic order of sequence `a` 1. Find the largest index j such that a[j] < a[j + 1]. If no such index exists, the permutation is the last permutation. 2. Find the largest index k greater than j such that a[j] < a[k]. 3. Swap the value of a[j] with that of a[k]. 4. Reverse the sequence from a[j + 1] up to and including the final element a[n]. ''' a = sorted(s) n = len(a) - 1 while True: yield ''.join(a) #1. Find the largest index j such that a[j] < a[j + 1] for j in range(n-1, -1, -1): if a[j] < a[j + 1]: break else: return #2. Find the largest index k greater than j such that a[j] < a[k] v = a[j] for k in range(n, j, -1): if v < a[k]: break #3. Swap the value of a[j] with that of a[k]. a[j], a[k] = a[k], a[j] #4. Reverse the tail of the sequence a[j+1:] = a[j+1:][::-1] for s in lexico_permute_string('data'): print(s)
salida
Por supuesto, si desea recopilar las cadenas producidas en una lista, puede hacerlo
list(lexico_permute_string('data'))
o en versiones recientes de Python:
[*lexico_permute_string('data')]
fuente
por qué no lo haces simple:
from itertools import permutations perms = [''.join(p) for p in permutations(['s','t','a','c','k'])] print perms print len(perms) print len(set(perms))
no obtiene ningún duplicado como puede ver:
['stack', 'stakc', 'stcak', 'stcka', 'stkac', 'stkca', 'satck', 'satkc', 'sactk', 'sackt', 'saktc', 'sakct', 'sctak', 'sctka', 'scatk', 'scakt', 'sckta', 'sckat', 'sktac', 'sktca', 'skatc', 'skact', 'skcta', 'skcat', 'tsack', 'tsakc', 'tscak', 'tscka', 'tskac', 'tskca', 'tasck', 'taskc', 'tacsk', 'tacks', 'taksc', 'takcs', 'tcsak', 'tcska', 'tcask', 'tcaks', 'tcksa', 'tckas', 'tksac', 'tksca', 'tkasc', 'tkacs', 'tkcsa', 'tkcas', 'astck', 'astkc', 'asctk', 'asckt', 'asktc', 'askct', 'atsck', 'atskc', 'atcsk', 'atcks', 'atksc', 'atkcs', 'acstk', 'acskt', 'actsk', 'actks', 'ackst', 'ackts', 'akstc', 'aksct', 'aktsc', 'aktcs', 'akcst', 'akcts', 'cstak', 'cstka', 'csatk', 'csakt', 'cskta', 'cskat', 'ctsak', 'ctska', 'ctask', 'ctaks', 'ctksa', 'ctkas', 'castk', 'caskt', 'catsk', 'catks', 'cakst', 'cakts', 'cksta', 'cksat', 'cktsa', 'cktas', 'ckast', 'ckats', 'kstac', 'kstca', 'ksatc', 'ksact', 'kscta', 'kscat', 'ktsac', 'ktsca', 'ktasc', 'ktacs', 'ktcsa', 'ktcas', 'kastc', 'kasct', 'katsc', 'katcs', 'kacst', 'kacts', 'kcsta', 'kcsat', 'kctsa', 'kctas', 'kcast', 'kcats'] 120 120 [Finished in 0.3s]
fuente
def permute(seq): if not seq: yield seq else: for i in range(len(seq)): rest = seq[:i]+seq[i+1:] for x in permute(rest): yield seq[i:i+1]+x print(list(permute('stack')))
fuente
Ver
itertools.combinations
oitertools.permutations
.fuente
Aquí hay una versión ligeramente mejorada del código de illerucis para devolver una lista de todas las permutaciones de una cadena
s
con caracteres distintos (no necesariamente en orden de clasificación lexicográfico), sin usar itertools:def get_perms(s, i=0): """ Returns a list of all (len(s) - i)! permutations t of s where t[:i] = s[:i]. """ # To avoid memory allocations for intermediate strings, use a list of chars. if isinstance(s, str): s = list(s) # Base Case: 0! = 1! = 1. # Store the only permutation as an immutable string, not a mutable list. if i >= len(s) - 1: return ["".join(s)] # Inductive Step: (len(s) - i)! = (len(s) - i) * (len(s) - i - 1)! # Swap in each suffix character to be at the beginning of the suffix. perms = get_perms(s, i + 1) for j in range(i + 1, len(s)): s[i], s[j] = s[j], s[i] perms.extend(get_perms(s, i + 1)) s[i], s[j] = s[j], s[i] return perms
fuente
Otra iniciativa más y solución recursiva. La idea es seleccionar una letra como pivote y luego crear una palabra.
# for a string with length n, there is a factorial n! permutations alphabet = 'abc' starting_perm = '' # with recursion def premuate(perm, alphabet): if not alphabet: # we created one word by using all letters in the alphabet print(perm + alphabet) else: for i in range(len(alphabet)): # iterate over all letters in the alphabet premuate(perm + alphabet[i], alphabet[0:i] + alphabet[i+1:]) # chose one letter from the alphabet # call it premuate(starting_perm, alphabet)
Salida:
fuente
Aquí hay una versión de generador realmente simple:
def find_all_permutations(s, curr=[]): if len(s) == 0: yield curr else: for i, c in enumerate(s): for combo in find_all_permutations(s[:i]+s[i+1:], curr + [c]): yield "".join(combo)
¡Creo que no es tan malo!
fuente
def f(s): if len(s) == 2: X = [s, (s[1] + s[0])] return X else: list1 = [] for i in range(0, len(s)): Y = f(s[0:i] + s[i+1: len(s)]) for j in Y: list1.append(s[i] + j) return list1 s = raw_input() z = f(s) print z
fuente
from itertools import permutations perms = [''.join(p) for p in permutations('ABC')] perms = [''.join(p) for p in permutations('stack')]
fuente
def perm(string): res=[] for j in range(0,len(string)): if(len(string)>1): for i in perm(string[1:]): res.append(string[0]+i) else: return [string]; string=string[1:]+string[0]; return res; l=set(perm("abcde"))
Esta es una forma de generar permutaciones con recursividad, puede comprender el código fácilmente tomando las cadenas 'a', 'ab' y 'abc' como entrada.
¡Obtienes todo N! permutaciones con esto, sin duplicados.
fuente
Todo el mundo ama el olor de su propio código. Solo comparto el que encuentro el más simple:
def get_permutations(word): if len(word) == 1: yield word for i, letter in enumerate(word): for perm in get_permutations(word[:i] + word[i+1:]): yield letter + perm
fuente
Este programa no elimina los duplicados, pero creo que es uno de los enfoques más eficientes:
s=raw_input("Enter a string: ") print "Permutations :\n",s size=len(s) lis=list(range(0,size)) while(True): k=-1 while(k>-size and lis[k-1]>lis[k]): k-=1 if k>-size: p=sorted(lis[k-1:]) e=p[p.index(lis[k-1])+1] lis.insert(k-1,'A') lis.remove(e) lis[lis.index('A')]=e lis[k:]=sorted(lis[k:]) list2=[] for k in lis: list2.append(s[k]) print "".join(list2) else: break
fuente
def permute_all_chars(list, begin, end): if (begin == end): print(list) return for current_position in range(begin, end + 1): list[begin], list[current_position] = list[current_position], list[begin] permute_all_chars(list, begin + 1, end) list[begin], list[current_position] = list[current_position], list[begin] given_str = 'ABC' list = [] for char in given_str: list.append(char) permute_all_chars(list, 0, len(list) -1)
fuente
Solución más sencilla mediante permutaciones.
from itertools import permutations def stringPermutate(s1): length=len(s1) if length < 2: return s1 perm = [''.join(p) for p in permutations(s1)] return set(perm)
fuente
Toda la palabra posible con pila
from itertools import permutations for i in permutations('stack'): print(''.join(i))
permutations(iterable, r=None)
Devuelve permutaciones de longitud r sucesivas de elementos en el iterable.
Si r no se especifica o es None, entonces r toma como valor predeterminado la longitud del iterable y se generan todas las posibles permutaciones de longitud completa.
Las permutaciones se emiten en orden lexicográfico. Entonces, si la entrada iterable está ordenada, las tuplas de permutación se producirán en orden ordenado.
Los elementos se tratan como únicos en función de su posición, no de su valor. Entonces, si los elementos de entrada son únicos, no habrá valores repetidos en cada permutación.
fuente
Esta es una solución recursiva con la
n!
que acepta elementos duplicados en la cadenaimport math def getFactors(root,num): sol = [] # return condition if len(num) == 1: return [root+num] # looping in next iteration for i in range(len(num)): # Creating a substring with all remaining char but the taken in this iteration if i > 0: rem = num[:i]+num[i+1:] else: rem = num[i+1:] # Concatenating existing solutions with the solution of this iteration sol = sol + getFactors(root + num[i], rem) return sol
Validé la solución teniendo en cuenta dos elementos, el número de combinaciones es
n!
y el resultado no puede contener duplicados. Entonces:inpt = "1234" results = getFactors("",inpt) if len(results) == math.factorial(len(inpt)) | len(results) != len(set(results)): print("Wrong approach") else: print("Correct Approach")
fuente
Aquí hay una implementación recursiva simple y directa;
def stringPermutations(s): if len(s) < 2: yield s return for pos in range(0, len(s)): char = s[pos] permForRemaining = list(stringPermutations(s[0:pos] + s[pos+1:])) for perm in permForRemaining: yield char + perm
fuente
stringPermutations
en una lista; puede iterar directamente sobre ella, por ejemplofor perm in stringPermutations(s[:pos] + s[pos+1:]):
. Además, se puede simplificar elfor
bucle utilizandoenumerate
en lugar derange
, y eliminar lachar = s[pos]
asignación:for pos, char in enumerate(s):
.# swap ith and jth character of string def swap(s, i, j): q = list(s) q[i], q[j] = q[j], q[i] return ''.join(q) # recursive function def _permute(p, s, permutes): if p >= len(s) - 1: permutes.append(s) return for i in range(p, len(s)): _permute(p + 1, swap(s, p, i), permutes) # helper function def permute(s): permutes = [] _permute(0, s, permutes) return permutes # TEST IT s = "1234" all_permute = permute(s) print(all_permute)
# swap ith and jth character of string def swap(s, i, j): q = list(s) q[i], q[j] = q[j], q[i] return ''.join(q) # iterative function def permute_using_stack(s): stk = [(0, s)] permutes = [] while len(stk) > 0: p, s = stk.pop(0) if p >= len(s) - 1: permutes.append(s) continue for i in range(p, len(s)): stk.append((p + 1, swap(s, p, i))) return permutes # TEST IT s = "1234" all_permute = permute_using_stack(s) print(all_permute)
# swap ith and jth character of string def swap(s, i, j): q = list(s) q[i], q[j] = q[j], q[i] return ''.join(q) # finds next lexicographic string if exist otherwise returns -1 def next_lexicographical(s): for i in range(len(s) - 2, -1, -1): if s[i] < s[i + 1]: m = s[i + 1] swap_pos = i + 1 for j in range(i + 1, len(s)): if m > s[j] > s[i]: m = s[j] swap_pos = j if swap_pos != -1: s = swap(s, i, swap_pos) s = s[:i + 1] + ''.join(sorted(s[i + 1:])) return s return -1 # helper function def permute_lexicographically(s): s = ''.join(sorted(s)) permutes = [] while True: permutes.append(s) s = next_lexicographical(s) if s == -1: break return permutes # TEST IT s = "1234" all_permute = permute_lexicographically(s) print(all_permute)
fuente