Permutation with recursion not printing all values in python? - python

I am writing python code to print all permutation of a number.
Below is my code:
a=[1,2,3,4]
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
def p(temp,i):
k=i+1
if k ==len(a)-1:
print(temp)
return
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
p(temp,i=0)
The idea is to replace every integer at first place and permutate remaining.
That's what this for loop is doing:
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
But,for every permutation starting with i,it only prints 4 permutations.
for ex:
Starting with 1,the permutations should be:
[1,2,3,4]
[1,2,4,3]
[1,3,2,4]
[1,3,4,2]
[1,4,3,2]
[1,4,2,3]
But,its only printing
[1,2,3,4]
[1,2,4,3]
[1,3,2,4]
[1,3,4,2]
4 at second place is not getting printed.
Missing:
[1,4,3,2]
[1,4,2,3]
Can anyone tell me what am I doing wrong?

Edited code:
def p(temp, k=0):
if k == len(temp):
print(temp)
return
for i in range(k, len(temp)):
temp[k], temp[i] = temp[i], temp[k]
p(temp, k+1)
temp[k], temp[i] = temp[i], temp[k]
p([1,2,3,4])
result:
[1, 2, 3, 4]
[1, 2, 4, 3]
[1, 3, 2, 4]
[1, 3, 4, 2]
[1, 4, 3, 2]
[1, 4, 2, 3]
[2, 1, 3, 4]
[2, 1, 4, 3]
[2, 3, 1, 4]
[2, 3, 4, 1]
[2, 4, 3, 1]
[2, 4, 1, 3]
[3, 2, 1, 4]
[3, 2, 4, 1]
[3, 1, 2, 4]
[3, 1, 4, 2]
[3, 4, 1, 2]
[3, 4, 2, 1]
[4, 2, 3, 1]
[4, 2, 1, 3]
[4, 3, 2, 1]
[4, 3, 1, 2]
[4, 1, 3, 2]
[4, 1, 2, 3]

Heres a correction for your process
a=[1,2,3,4]
def p(temp,i):
k=i+1
if k ==len(a)-1:
print(temp)
return
temp[k],temp[k+1]=temp[k+1],temp[k]
prev = temp.copy()
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
p(temp,k)
temp[k],temp[k+1]=temp[k+1],temp[k]
if temp != prev:
p(temp,k)
for i in range(len(a)):
temp=a[:]
temp[0],temp[i]=temp[i],temp[0]
p(temp,i=0)
The problem was that you were only rearranging the temp list 2 times in the actual call of the function p from the for loop. Calling it three times made it to contain '4' in the second place of the permutation. The if statement I added is to check if the previous rearranged temp is not the as the current rearrange temp, this removed duplicate results which occurred when calling the function p three times. Although I do recommend Hamid's answer.

The logic seems to be wrong. You are swapping the neighboring elements. Because of that, you are unable to generate all the permutations. Ideally, you want to recursively repeat the logic of fixing the first element.

Related

Split one list of numbers into several based on a simple condition, lead and lag in lists [duplicate]

This question already has answers here:
Split List By Value and Keep Separators
(8 answers)
Closed 1 year ago.
Is there an easy way to split the list l below into 3 list. I want to cut the list when the sequence starts over. So every list should start with 1.
l= [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
l1 = [1, 2, 3,4, 5]
l2=[1,2,3,4]
l3=[1,2,3,4]
My original thought was to look at the lead value and implement a condition inside a for loop that would cut the list when x.lead < x. But how do I use lead and lag when using lists in python?
NumPy solution
import numpy as np
l = [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
parts = [list(i) for i in np.split(l,np.flatnonzero(np.diff(l)-1)+1)]
print(parts)
output
[[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 4]]
Explanation: I first find differences between adjacent elements using numpy.diff, then subtract 1 to be able to use numpy.flatnonzero to find where difference is other than 1, add 1 (note that numpy.diff output length is input length minus 1) to get indices for use in numpy.split, eventually convert it to list, as otherwise you would end with numpy.arrays
What about this:
l = [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
one_indices = [i for i, e in enumerate(l) if e == 1]
slices = []
for count, item in enumerate(one_indices):
if count == len(one_indices) - 1:
slices.append((item, None))
else:
slices.append((item, one_indices[count + 1]))
sequences = [l[x[0] : x[1]] for x in slices]
print(sequences)
Out:
[[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2, 3, 4]]
Another way without numpy,
l= [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]
start = 0
newlist = []
for i,v in enumerate(l):
if i!=0 and v==1:
newlist.append(l[start:i])
start = i
newlist.append(l[start:i+1])
print(newlist)
Working Demo: https://rextester.com/RYCV85570

How to weave two lists using recursion in Python

I want to weave two lists and output all the possible results.
For example,
input: two lists l1 = [1, 2], l2 = [3, 4]
output: [1, 2, 3, 4], [1, 3, 2, 4], [1, 3, 4, 2], [3, 1, 2, 4], [3, 1, 4, 2], [3, 4, 1, 2]
Note: I need to keep the order in each list (e.g. 1 is always before 2, and 3 is always before 4)
The way I am solving this is by removing the head from one list, recursing, and then doing the same thing with the other list. The code is below:
all_possibles = []
def weaveLists(first, second, added):
if len(first) == 0 or len(second) == 0:
res = added[:]
res += first[:]
res += second[:]
all_possibles.append(res)
return
cur1 = first[0]
added.append(cur1)
first = first[1:]
weaveLists(first, second, added)
added = added[:-1]
first = [cur1] + first
cur2 = second[0]
added.append(cur2)
second = second[1:]
weaveLists(first, second, added)
added = added[:-1]
second = [cur2] + second
weaveLists([1, 2], [3, 4], [])
print(all_possibles)
The result I got is:
[[1, 2, 3, 4], [1, 3, 2, 4], [1, 3, 4, 2], [1, 3, 1, 2, 4], [1, 3, 1, 4, 2], [1, 3, 1, 4, 1, 2]]
I couldn't figure out why for the last three lists, the heading 1 from the first list is not removed.
Can anyone help? Thanks!
The reason you get those unexpected results is that you mutate added at this place:
added.append(cur1)
...this will affect the caller's added list (unintentionally). While the "undo" operation is not mutating the list:
added = added[:-1]
This creates a new list, and therefore this "undo" action does not roll back the change in the list of the caller.
The easy fix is to replace the call to append with:
added = added + [cur1]
And the same should happen in the second block.
It is easier if you pass the new values for the recursive call on-the-fly, and replace those two code blocks with just:
weaveLists(first[1:], second, added + [first[0]])
weaveLists(first, second[1:], added + [second[0]])
Here is another way to do it: we generate the possible indices of the items of the first list inside the weaved list, and fill the list accordingly.
We can generate the indices with itertools.combinations: it's the combinations of the indices of the weaved list, taking len(first_list) of them each time.
from itertools import combinations
​
def weave(l1, l2):
total_length = len(l1) + len(l2)
# indices at which to put items from l1 in the weaved output
for indices in combinations(range(total_length), r=len(l1)):
out = []
it1 = iter(l1)
it2 = iter(l2)
for i in range(total_length):
if i in indices:
out.append(next(it1))
else:
out.append(next(it2))
yield out
Sample run:
l1 = [1, 2]
l2 = [3, 4]
​
for w in weave(l1, l2):
print(w)
​
[1, 2, 3, 4]
[1, 3, 2, 4]
[1, 3, 4, 2]
[3, 1, 2, 4]
[3, 1, 4, 2]
[3, 4, 1, 2]
Another sample run with a longer list:
l1 = [1, 2]
l2 = [3, 4, 5]
​
for w in weave(l1, l2):
print(w)
​
[1, 2, 3, 4, 5]
[1, 3, 2, 4, 5]
[1, 3, 4, 2, 5]
[1, 3, 4, 5, 2]
[3, 1, 2, 4, 5]
[3, 1, 4, 2, 5]
[3, 1, 4, 5, 2]
[3, 4, 1, 2, 5]
[3, 4, 1, 5, 2]
[3, 4, 5, 1, 2]

Why does recursion overwrite values in a list that is passed along?

This recusion is adapted from http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/ and does indeed print out all possible unique combination of arr with length r.
What I want from it is to save all possible combination in a list to further use this algorithm in another program. Why is the values overritten in combArray in the recustion and how do I solve this?
def combRecursive(arr, data, start, end, index, r, combArray):
if index == r:
combArray.append(data)
return combArray
i = start
while True:
if i > end or end - i + 1 < r - index:
break
data[index] = arr[i]
combArray = combRecursive(arr, data, i + 1, end, index + 1, r, combArray)
i += 1
return combArray
def main():
arr = [1, 2, 3, 4, 5]
r = 3
n = len(arr)
data = [9999999, 9999999, 9999999]
combArray = []
combArray = combRecursive(arr, data, 0, n-1, 0, r, combArray)
print("All possible unique combination is: ")
for element in combArray:
print(element)
Result as of now:
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
[3, 4, 5]
What I want:
[1, 2, 3]
[1, 2, 4]
[1, 2, 5]
[1, 3, 4]
[1, 3, 5]
[1, 4, 5]
[2, 3, 4]
[2, 3, 5]
[2, 4, 5]
[3, 4, 5]
You initialize data, and from then on make changes to it & add it to combArray, which means you are always adding the same array to combArray, so all of its elements are the same. If you want the elements to be distinct arrays, you need to make a new array for each you want to add to combArrays (by, for example, making a copy of data).

Accumulating results of a recursive function in python

Consider the following function to permute numbers in a list:
def permute(numbers, N=0):
# base case
if N == len(numbers):
print numbers
return
for i in range(len(numbers)-N):
# swapping relevant elements
element=numbers.pop(N+i)
numbers.insert(N,element)
# recursive call
permute(numbers, N+1)
# swapping back relevant elements when backtracking
element=numbers.pop(N)
numbers.insert(N+i,element)
numbers=[1,2,3]
permute(numbers)
Why is it that when I run the above code, it produces the correct output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
but when I'm trying to accumulate the result to a list:
def permute(numbers, permutations, N=0):
# base case
if N == len(numbers):
print numbers
permutations.append(numbers)
return
for i in range(len(numbers)-N):
# swapping relevant elements
element=numbers.pop(N+i)
numbers.insert(N,element)
# recursive call
permute(numbers, permutations, N+1)
# swapping back relevant elements when backtracking
element=numbers.pop(N)
numbers.insert(N+i,element)
numbers=[1,2,3]
permutations=[]
permute(numbers, permutations)
print "-----------"
for p in permutations:
print p
The output is this:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
-----------
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
Not quite what I expected...
All of the items you're appending to permutations are actually the same list. Changing one changes all of the others. The easiest fix for this is to make a copy of the list before appending it, so future changes to numbers has no effect on the already-appended results.
def permute(numbers, permutations, N=0):
# base case
if N == len(numbers):
print numbers
permutations.append(numbers[:])
return
Result:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
---------
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

Python : Generating cyclic permutations code (An unexpected code error to be clarified)

I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]

Categories

Resources