Reputation: 3
Im trying to replicate the function from itertools.permutations()
for purely didactic reasons.
One way of doing it was using lists of 1s, where 0 marks that a given elements has already being used.
So for instance, a list of letters:
list_l = ['a','b','c']
and the list [0,1,1]
marks that a
has already being used.
I pass this list to same function, and it generates the sublists [0,0,1]
and [0,1,0]
which corresponds to letters b being selected and c by elimination for the first list and c and then b for the second.
This method of marking the letters in positions of a list, requires me to keep an historial for each position of the combination, so even though I get the correct result I would like to make the function a generator giving one result at a time, but I don't know how to do it without breaking the recursivity and therefore destroying the program. I need the return for keeping the historial clean for the next element to be generated and i doubt it is possible to use yield and return in parallel.
I leave my code here. Thank you
def generate_string(list, a):
comb = ''
for n, v in enumerate(a[0]):
if v==0:
comb = comb + lista[n]
for i in range(len(a)-1):
for n,j in enumerate(zip(a[i], a[i+1])):
if j[0] != j[1]:
comb = comb + lista[n]
for n, v in enumerate(a[-1]):
if v==1:
comb = comb + lista[n]
return comb
def comb(lista, uns = None, historial = []):
if uns == None:
l = [1] *len(lista)
comb(lista, uns = l)
else:
if sum(uns) == 1:
print(generate_string(lista, historial).upper())
return historial[:-1]
else:
for n, valor in enumerate(uns):
uns2 = copy.deepcopy(uns)
if valor == 1:
uns2[n] = 0
historial.append(uns2)
historial = comb(lista, uns2, historial)
return historial[:-1]
lista = ['a','b','c','d']
comb(lista)
Upvotes: 0
Views: 108
Reputation: 54698
Here is the recursive way to do permutations. The theory here is that, for each element in the list, you generate that element PLUS the permutations of the other elements in the list. Eventually, you get down to a spot where there are no more options to permute, and at that point you have a complete permutation to return. "yield from" is a passthrough, just passing the complete permutations yielded from the deeper calls.
lst = ['a','b','c','d']
def perm(lst, pfx=[]):
if not lst:
yield pfx
for i in range(len(lst)):
yield from perm( lst[0:i]+lst[i+1:], pfx+[lst[i]] )
print( list(perm(lst)))
Upvotes: 1