Python permutations recursive - python

I'm trying to solve a problem using backtracking and I need the permutations of numbers for it. I have this basic algorithm that does it but the problem is... the results don't come in the normal order.
def perm(a,k=0):
if(k==len(a)):
print(a)
else:
for i in range(k,len(a)):
a[k],a[i] = a[i],a[k]
perm(a, k+1)
a[k],a[i] = a[i],a[k]
Example: for [1,2,3] the normal results would be: [1,2,3] [1,3,2] [2,1,3] [2,3,1] [3,1,2] [3,2,1]
Whereas this algorithm will interchange the last 2 elements. I understand why. I just don't know how to correct this.
I don't want to use the permutations from itertools. Can the code above be easily fixed to work properly? What would be the complexity for this algorithm from above?

A recursive generator function that yields permutations in the expected order with regard to the original list:
def perm(a):
if len(a) <= 1:
yield a
else:
for i in xrange(len(a)):
for p in perm(a[:i]+a[i+1:]):
yield [a[i]]+p
a = [1, 2, 3]
for p in perm(a):
print(p)
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

Here's one (suboptimal, because copying lists all the time) solution:
def perm(a, prev=[]):
if not a:
print(prev)
for index, element in enumerate(a):
perm(a[:index] + a[index+1:], prev + [element])
‌The order it is printed out:
>>> perm([1,2,3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

Related

Quantity of subarrays in a pythonic way

I have this array:
[1,2,3,4]
and I want all the sub arrays you can get except by the single element, in this case:
[1,2],[1,2,3],[1,2,3,4],[2,3],[2,3,4],[3,4].
So I have implemented this code:
def nSub(nums:list):
"""
type nums: list
"""
l_nums = len(nums)
p = 2
for i in range(l_nums):
for j in range(p,l_nums+1):
print(nums[i:j])
p += 1
nSub([1,2,3,4])
But although it works, perhaps there is other way to implement this, so I have this question: is there a pythonic way to do this? Any help will be greatly appreciated.
Simple list comprehension should do the job:
arr = [1,2,3,4]
[arr[n1:n2]
for n1 in range(0, len(arr) + 1)
for n2 in range(n1 + 2, len(arr) + 1)]
Output:
[[1, 2], [1, 2, 3], [1, 2, 3, 4], [2, 3], [2, 3, 4], [3, 4]]

After using combinations with replacement, how to remove tuples with combinations that I don't want

I'm trying to get a list of lists (or tuples) which follows a pattern something like this:
[1,1,1,2]
[1,1,2,2]
[1,2,2,2]
[1,2,2,3]
[1,2,3,3]
[1,2,3,4]
Using itertools.combinations_with_replacement I've gotten close, but I end up with lists which jump values for example:
[1,1,1,3]
or
[2,2,2,3]
I don't want this. I always want to start at 1, and increase until the list is filled, and then increase to the next value.
If I'm using itertools, then is there a way to remove the lists that I don't want?
Instead of using combinations, I would generate the pattern directly.
Create a list of 1's with the desired length and iterate backward, changing the list accordingly.
def generate_increment(n):
lst = [1] * n
result = []
for k in range(n-1):
lst[-1] += 1
result.append(lst[:])
for i in range(len(lst)-2, k, -1):
a, b = lst[i], lst[i+1]
if a != b:
lst[i] = b
result.append(lst[:])
return result
>>print(*generate_increment(4), sep='\n')
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]
It feels like validating the results of combinations will be a bigger effort than simply creating those lists you need.
This can be done with a recursive function that adds with each step what value to add to the list until a defined size:
def gen_list(pre, size):
if size == 1:
return [pre]
res = gen_list(pre + [pre[-1]], size - 1)
res.extend(gen_list(pre + [pre[-1]+1], size-1))
return res
for l in gen_list([1], 4):
print(l)
Which prints:
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 1, 2, 3]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]

Generate all combinations of 2 lists (game playing)

I am trying to generate all possible combinations between 2 lists A and B in python with a few constraints. A and B alternate in picking values, A always picks first. A and B may have overlapping values. If A has already picked a value, then B cannot pick it, and vice versa.
Both lists need not be of equal lengths. If one list has no available values to pick then I stop generating combinations
Also the elements picked by each must be in increasing order, i.e. A[1] < A[2] < .... A[n] and B[1] < B[2] < .... B[n] where A[i] and B[i] is the i-th element picked by A and B respectively
Example:
A = [1, 2, 3, 4]
B = [2, 5]
Solution I need is
(1), (2), (3), (4),
(1,2), (1,5), (2,5), (3,2), (3,5), (4,2), (4,5),
(1,2,3), (1,2,4), (3,2,4), (1,5,2), (1,5,3), (1,5,4), (2,5,3), (2,5,4), (3,5,4),
(1,2,3,5), (1,2,4,5), (3,2,4,5)
(1,2,3,5,4)
I believe itertools in python can be useful for this but I havent really figured out how to implement it for this case.
As of now, this is how I am solving it:
A = [1, 2, 3, 4]
B = [2, 5]
A_set = set(A)
B_set = set(b)
#Append both sets
C = A.union(B)
for L in range(len(C), 0, -1):
for subset in itertools.combinations(C, L):
#Check if subset meets constraints and print it if it does
As noted in comments, this is probably much too specific to be easily solved using itertools, and you should use a recursive (generator) function instead. Just pick the next element from whichever list's turn it is, keeping track of the elements already selected, and recursively call the function again, swapping and shortening the lists and adding the element to the set of selected elements, until you've got the required number.
Something like this (this might be improved by adding parameters for the current index in both lists instead of actually slicing the lists for the recursive calls):
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
for i, x in enumerate(lst1):
if x not in selected:
selected.add(x)
for rest in solve(n-1, lst2, lst1[i+1:], selected):
yield [x] + rest
selected.remove(x)
Or a bit more condensed:
def solve(n, lst1, lst2, selected):
if n == 0:
yield []
elif lst1:
yield from ([x] + rest for i, x in enumerate(lst1) if x not in selected
for rest in solve(n-1, lst2, lst1[i+1:], selected.union({x})))
Example:
A = [1, 2, 3, 4]
B = [2, 5]
result = [res for n in range(1, len(A)+len(B)+1) for res in solve(n, A, B, set())]
Afterwards, result is:
[[1], [2], [3], [4],
[1, 2], [1, 5], [2, 5], [3, 2], [3, 5], [4, 2], [4, 5],
[1, 2, 3], [1, 2, 4], [1, 5, 2], [1, 5, 3], [1, 5, 4], [2, 5, 3], [2, 5, 4], [3, 2, 4], [3, 5, 4],
[1, 2, 3, 5], [1, 2, 4, 5], [3, 2, 4, 5],
[1, 2, 3, 5, 4]]

How to print different parts of a list on new line in Python?

I have two lists, one is of a known length and the other is a random length:
MyList1 = [[1, 2, 3], [4, 5],[5, 6, 7, 8]].
MyList2 = [1, 2, 3, 4 ,5 ,6 ]
I need to print the second one in the following way, where 3 lines is for the number of objects in the first list:
[1, 2, 3]
[4, 5]
[6]
The problem is that I don't know the exact length of this list and the sizes of the lines may not be equal.
I got stuck on doing it with for loop, but it doesn't seem to work.
A while loop will do the trick better.
list1 = [1, 2, 3]
list2 = [1, 2, 3, 4, 5 ,6 ]
start = 0
while start < len(list2):
print list2[start:start+len(list1)]
start += len(list1)
Based on your last comment, I think the following will work for you:
>>> l1
[[1, 2, 3], [4, 5], [5, 6, 7, 8]]
>>> l2
[1, 2, 3, 4, 5, 6]
>>> i,s=0,0
>>> while s < len(l2):
print l2[s:s+len(l1[i])]
s += len(l1[i])
i += 1
[1, 2, 3]
[4, 5]
[6]
If you're curious how to use a for loop:
step_size = int(len(list2)/len(list1))
for i in range(0, len(list1) - 1):
start = i * step_size
end = start + step_size
print(list2[start:end])
print(list2[len(list1)*step_size - step_size:])
The print after the loop prints the last chunk, which might be a different size than the others.
You can try generator function like this,
my_list1 = [1, 2, 3, 4 ,5 ,6 ]
my_list2 = [1, 2, 3]
def make_list(lst1, lst2):
item_count = len(lst1) / len(lst2)
for ix in range(0, len(lst1), item_count):
yield lst1[ix:ix + item_count]
print list(make_list(my_list1, my_list2))

The append operation of list

class Solution:
"""
#param nums: A list of Integers.
#return: A list of permutations.
"""
def permute(self, nums):
# write your code here
result = []
if nums is None:
return result
self.permution(nums, 0, result)
return result
def permution(self, array, k, result):
if k == len(array):
print array
result.append(array)
else:
for i in xrange(k, len(array)):
array[i], array[k] = array[k], array[i]
self.permution(array, k+1, result)
array[i], array[k] = array[k], array[i]
if __name__=="__main__":
print Solution().permute([1, 2, 3])
This is my code about permutations. When I output the answer, I found the problem.
If I use print array,the output is
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]
and it's right. But when I use result.append(array),the output is
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
I don't understand why it's not the same.
This is a simple call_by_reference issue. You are passing the array by reference not by value in each recursion. Since the array is passed by reference the changes in any recursive step applies to all sub-arrays in result because each sub-array is a reference of the same array. To get the correct result do as follows:
Replace:
self.permution(array, k+1, result)
with:
self.permution(array[:], k+1, result)
For more details on the topic see passing arguments.

Categories