Array gets swapped before swap function is used [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
I am trying to write a simple swap function, where the elements of an array get swapped once. The idea is I want to swap it once and check if it is the same as the unswapped array (which it will be for some cases, when all the elements are same, or something like that)
def swap(arr, pos):
if pos <= len(arr) - 1 and num != 0:
arr[pos], arr[pos + 1] = arr[pos + 1], arr[pos]
else:
pass
return arr
some = [1,2,3,4]
#print(some)
for i in range(len(some) - 1):
arr0 = some
arr1 = swap(some, i)
print(arr0, arr1)
And the output for this is:
[2, 1, 3, 4] [2, 1, 3, 4]
[2, 3, 1, 4] [2, 3, 1, 4]
[2, 3, 4, 1] [2, 3, 4, 1]
And I'm expecting something like:
[1, 2, 3, 4] [2, 1, 3, 4]
...
Why does the arr0 array get swapped?

arr0 = some[:]
this should help you, it will copy the instance of the array not the location of it because when you make change to your some this will effect every array that is a directional copy of it

use copy() method.
arr0 = some.copy()
Code:
def swap(arr, pos):
if pos <= len(arr) - 1 and num != 0:
arr[pos], arr[pos + 1] = arr[pos + 1], arr[pos]
else:
pass
return arr
some = [1,2,3,4]
#print(some)
for i in range(len(some) - 1):
arr0 = some.copy()
arr1 = swap(some, i)
print(arr0, arr1)
Output:
[1, 2, 3, 4] [2, 1, 3, 4]
[2, 1, 3, 4] [2, 3, 1, 4]
[2, 3, 1, 4] [2, 3, 4, 1]

Other answers have made it clear. I just want to say, why not write
def swap(arr, pos):
if pos <= len(arr) - 1 andpos < 0:
arr[pos], arr[pos + 1] = arr[pos + 1], arr[pos]
else:
pass
return arr
some = [1,2,3,4]
#print(some)
for i in range(len(some) - 1):
print("before swap: ", some)
swap(some, i)
print("after swap: ", some)
Then you do not need to copy the list. Just print swap log in two lines.

Related

elements to python list

iterating and appending a list to another list but printing unexpected output: what is wrong?
the last output contains the same elements overwriting the appended elements at
each iteration.
def pascal(n):
"""
print pascal triangle
"""
list = []
if (n > 0):
lst = []
for line in range(1, n + 1):
k = 1
lst.clear()
for i in range(1, line + 1):
lst.append(k)
k = int(k * (line - i)/i)
print(lst)
list.append(lst)
print (list)
else:
print (list)
pascal(5)
**output:**
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[[1, 4, 6, 4, 1], [1, 4, 6, 4, 1], [1, 4, 6, 4, 1], [1, 4, 6, 4, 1], [1, 4, 6, 4, 1]]
**expected output:**
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[[1,], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
def pascal(n):
"""
print pascal triangle
"""
lis = []
if (n > 0):
lst = []
for line in range(1, n + 1):
k = 1
lst.clear()
print(lst,lis) # This is what happening .. your result lis is become empty while you trying to clear lst..! and in the last lst contains value are stored in all the list of lists.
for i in range(1, line + 1):
lst.append(k)
k = int(k * (line - i)/i)
#print(lst)
lis.append(lst)
#print(lis)
else:
print(lis)
pascal(5)
Output:-
[] []
[] [[]]
[] [[], []]
[] [[], [], []]
[] [[], [], [], []]
Reason. In above code list of lists reference the same object. This is because of the fact that lists are referential structures in python. when the last loop iterates lsi store the value in lis in all list of lists..
You can do..
def pascal(n):
"""
print pascal triangle
"""
lis = []
if (n > 0):
for line in range(1, n + 1):
lst = []
k = 1
for i in range(1, line + 1):
lst.append(k)
k = int(k * (line - i)/i)
print(lst)
lis.append(lst)
print(lis)
else:
print(lis)
pascal(5)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]
also not initalise list with a name list as it is a built-in data type..!
Create a new list on each iteration instead of mutating the same one each time.
res = []
if n > 0:
for line in range(1, n + 1):
k = 1
curr = []
for i in range(1, line + 1):
curr.append(k)
k = int(k * (line - i)/i)
print(curr)
res.append(curr)
print(res)

How do I count the number of a list appears in another list?

I have a list named A:
A = [1, 2, 1, 2, 1, 2, 3, 4, 5]
and I want to count the number of list [1, 2] appears in A.
It will be 3 because:
A = [1, 2, 1, 2, 1, 2, 3, 4, 5]
[1, 2][1, 2][1, 2] <- appears 3 times
Here is my code:
result = 0
while len(A) > 0:
temp, tA = [1, 2], A
for i in temp:
if len(tA) == 0: break
if i in tA: tA.pop(0)
result += 1
return result
And I wonder know is there any faster way to accomplish the same function?

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]

Developing an indexing scheme for list of all non-decreasing sequences

Suppose that we are considering a sorted list of all non-decreasing sequences with values in the range (1, max_num) and num_slots elements in each sequence, how can I find the index of some given member sequence in O(1) time complexity? I am not actually given the entire list up-front, I just want to find the index of some member sequence were the list of all sequences to exist.
For a concrete example, suppose that max_num = 3 and num_slots = 4. Then there are 15 sequences (or generally, there are (max_num + num_slots - 1) choose (num_slots) sequences):
[[1, 1, 1, 1],
[1, 1, 1, 2],
[1, 1, 1, 3],
[1, 1, 2, 2],
[1, 1, 2, 3],
[1, 1, 3, 3],
[1, 2, 2, 2],
[1, 2, 2, 3],
[1, 2, 3, 3],
[1, 3, 3, 3],
[2, 2, 2, 2],
[2, 2, 2, 3],
[2, 2, 3, 3],
[2, 3, 3, 3],
[3, 3, 3, 3]]
So given inputs of a sequence like [1, 2, 2, 3] along with the information max_num = 3, I am trying to write a function that would return its correct index of 7. I do not actually have the list of all sequences to work with.
Background info
I have come up with an algorithm to generate all non-decreasing sequences I care about, but this doesn't seem completely relevant for generating the index of a particular member sequence without the whole list of sequences materialized.
def gen(max_num, num_slots, l = None):
if l is None:
l = [[1] * num_slots]
cur = l[-1].copy()
for i in reversed(range(num_slots)):
if cur[i] < max_num:
cur[i] += 1
for j in range(i+1, num_slots):
cur[j] = cur[i]
l.append(cur)
return gen(max_num, num_slots, l)
return l
This one is O(|seq| + max_num). Note that this is still much faster than the naive generate all and search approach, which is exponential in |seq|.
The idea is that you count the sequences before the input sequence. For example,
you want to know what's the index of [2, 4, 5, 6] when max_num = 6.
Count [1, *, *, *]
Count [2, 2, *, *]
Count [2, 3, *, *]
(Note: you cannot count [2, 4, *, *], because then you would include [2, 4, 6, 6] which comes after your input. You should always go until one less than your input at the given index)
Count [2, 4, 4, *]
Count [2, 4, 5, 5]
(for each row, you can use your formula, (max_num + num_slots - 1) choose (num_slots) and sum them up)
def combinations(slots, available):
return choose(slots + available - 1, slots)
def find_index(seq, max_num):
res = 0
for digit_index in xrange(len(seq)):
prev = seq[digit_index - 1] if digit_index > 0 else 1
for digit in xrange(prev, seq[digit_index]):
res += combinations(len(seq) - digit_index - 1, max_num - digit + 1)
return res
print find_index([1, 2, 2, 3], 3)
I'll elaborate on #DavidFrank's answer on why it is O(length+max_num) and give a more easily understand example (a bit more complex too).
To start with, observe:
Assume the total series possibility in F(length, max_num) = X
Then for all of possibilities in X that starts with 1, e.g. [1, ....], we have a count of F(length-1, max_num) within this group.
For all the possibility in X that does not start with 1, e.g. [2, ....] or [3, ....], we have a count of F(length, max_num-1).
Thus we can use recursion to get this in O(length*max_num) (can become O(length+max_num) if we use memoization) number of complexity:
# This calculate the total number of X of possible entry given (length, max_num)
def calc_sum(length, max_num):
if max_num == 1:
return 1
elif length == 1:
return max_num
else:
total = calc_sum(length-1, max_num) + calc_sum(length, max_num-1)
return total
Now we examine the result to see if we can make it O(1):
# This is clearly not going to make it O(1), so now we need some generalizations to NOT run this recursion.
import numpy as np
arr = np.zeros((6,6))
for i in range(6):
for j in range(6):
arr[i, j] = calc_sum(i+1, j+1)
print(arr)
The result is:
[[ 1. 2. 3. 4. 5. 6.]
[ 1. 3. 6. 10. 15. 21.]
[ 1. 4. 10. 20. 35. 56.]
[ 1. 5. 15. 35. 70. 126.]
[ 1. 6. 21. 56. 126. 252.]
[ 1. 7. 28. 84. 210. 462.]]
This is a pascal's triangle, if you look diagonally to the top right. The diagonals of pascal's triangle are defined by (x choose y)
This makes it clear that it cannot be O(1), and will at least be O(length+max_num) because this is the general complexity of (Choose) function.
We've went all the way to prove that an O(1) solution is impossible, unless we constrain (length + max_num) to be constant.
# We can expand by solving it now:
from scipy.special import comb # this is choose function.
def get_index(my_list, max_num):
my_list = np.array(my_list)
if len(my_list) == 1:
return my_list[0] - 1
elif my_list[0] == 1:
return get_index(my_list[1:], max_num)
elif my_list[0] != 1:
return get_index(my_list - 1, max_num - 1) + comb(len(my_list)-2+max_num, max_num-1)
get_index([1,2,2,3],3) # 7
The aggregated complexity of the final function with the comb() is still O(length + max_num) as the complexity of everything outside comb is O(length + max_num) as well.
There is bijection from the k-subsets of {1...n} (with repetition) to k-subsets of {1...n + k − 1} (without repetition) by mapping {c_0, c_1...c_(k−1)} to {c_0, c_(1+1), c_(2+2)...c_(k−1+k−1)} (see here).
Once converted, just use your favourite combination ranking utility.
[3, 3, 3, 3] --> [3, 4, 5, 6]
[2, 3, 3, 3] --> [2, 4, 5, 6]
[2, 2, 3, 3] --> [2, 3, 5, 6]
[2, 2, 2, 3] --> [2, 3, 4, 6]
[2, 2, 2, 2] --> [2, 3, 4, 5]
[1, 3, 3, 3] --> [1, 4, 5, 6]
[1, 2, 3, 3] --> [1, 3, 5, 6]
[1, 2, 2, 3] --> [1, 3, 4, 6]
[1, 2, 2, 2] --> [1, 3, 4, 5]
[1, 1, 3, 3] --> [1, 2, 5, 6]
[1, 1, 2, 3] --> [1, 2, 4, 6]
[1, 1, 2, 2] --> [1, 2, 4, 5]
[1, 1, 1, 3] --> [1, 2, 3, 6]
[1, 1, 1, 2] --> [1, 2, 3, 5]
[1, 1, 1, 1] --> [1, 2, 3, 4]
import pyncomb
def convert(m, S):
return (m + len(S) - 1, [ x-1 + i for x,i in zip(S, list(xrange(len(S)))) ])
def rank(m, S):
k, s = convert(m, S)
return pyncomb.ksubsetcolex.rank(k, s)
print rank(3, [1,2,2,3])
# 7
For each digit, find the difference between that and the lowest digit. Add 1 for each changed position to the right of any altered digit
idx = 0;
for i in range(0,num_slots):
d = SEQ[i]
idx += d-min_num
if (d > min_num):
idx += num_slots-1 - i
For example:
[1,1,1,3] is 0 + 0 + 0 + (2+0) or 2
[1,2,3,3] is 0 + (1+2) + (2+1) + (2+0) or 8
[3,3,3,3] is (2+3) + (2+2) + (2+1) + (2+0) or 14

arrangements backtracking python

I have a hard time trying to figure out how to generate the arrangements via backtracking on python, it is something they asked us at university
A group of n (n<=10) persons, numbered from 1 to n are placed on a row
of chairs, but between every two neighbor persons some conflict of
interests appeared. Display all the possible modalities to replace the
persons, such that between any two persons in conflict stays one or at
most two other persons.
I managed to modify the code for the permutations and the queens but i don`t really know where to put the condition for example k is the number and k must be different from the previous number in the string +1 and must bee different from the next number+1
The list of person sitting on the chairs is 1 2 3 4 (is impossible for less then 3 persons)
one right solution will be 1 3 4 2 and 3 1 4 2
Here is the code:
class Permutations(Backtracking):
def __init__(self, n):
Backtracking.__init__(self, n)
def _init_value(self, k):
return 0
def _next_value(self, n, k, v):
if v < n:
return v + 1
return None
def _cond(self, k, possible, v):
if v is None:
return False
try:
possible[:k].index(v)
return False
except ValueError:
return True
def _solution(self, n, k, possible):
return k == n-1
def _handle_solution(self, n, k, possible):
print(possible)
def chairs(soln, i=0):
if i == len(soln):
yield tuple(soln)
for j in xrange(i, len(soln)):
if i == 0 or soln[j] not in (soln[i - 1] + 1, soln[i - 1] - 1):
soln[i], soln[j] = soln[j], soln[i]
for s in chairs(soln, i + 1):
yield s
soln[i], soln[j] = soln[j], soln[i]
print list(chairs(range(1, 5)))
Code:
def possible_solution(remaining, sol=None):
sol = sol or []
if not remaining:
yield sol
else:
for i, candidate in enumerate(remaining):
if not sol or abs(sol[-1] - candidate) != 1:
new_sol = sol + [candidate]
new_remaining = remaining[:i] + remaining[i+1:]
for x in possible_solution(new_remaining, new_sol):
yield x
Test code:
def possible_solutions(neighbors):
for solution in possible_solution(neighbors):
print solution
print '-' * 30
possible_solutions([1, 2, 3])
print '-' * 30
possible_solutions([1, 2, 3, 4])
print '-' * 30
possible_solutions([1, 2, 3, 4, 5])
Results:
------------------------------
------------------------------
[2, 4, 1, 3]
[3, 1, 4, 2]
------------------------------
[1, 3, 5, 2, 4]
[1, 4, 2, 5, 3]
[2, 4, 1, 3, 5]
[2, 4, 1, 5, 3]
[2, 5, 3, 1, 4]
[3, 1, 4, 2, 5]
[3, 1, 5, 2, 4]
[3, 5, 1, 4, 2]
[3, 5, 2, 4, 1]
[4, 1, 3, 5, 2]
[4, 2, 5, 1, 3]
[4, 2, 5, 3, 1]
[5, 2, 4, 1, 3]
[5, 3, 1, 4, 2]

Categories