Weird list append bug in Python? [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
How to deep copy a list?
(10 answers)
How to get all subsets of a set? (powerset)
(32 answers)
Closed 1 year ago.
I'm trying to write a function in python that returns the powerset of a list inputted to it. In lines 5 and 6, I try to append an element to only the second half of the array but it apparently gets appended to all the elements of the array. Why does this happen and how can I fix it?
Code:
def powerset(array):
ans=[[]]
for elem in array:
ans.extend(ans.copy())
for j in range(int(len(ans)/2), len(ans)):
ans[j].append(elem)
return ans
Example input: [0, 1]
Output returned by above function: [[0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
Expected Output: [[], [0], [1], [0, 1]]

You're making a shallow copy of ans, means the elements inside the list in ans are not copied, they remain the same.
Use copy.deepcopy().
from copy import deepcopy
def powerset(array):
ans=[[]]
for elem in array:
ans.extend(deepcopy(ans))
for j in range(int(len(ans)/2), len(ans)):
ans[j].append(elem)
return ans
print(powerset([0, 1]))
Output:
[[], [0], [1], [0, 1]]

Related

need help understanding how python arrays work [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed last year.
So I'm trying to create an array visualiser with pygame and have run into a strange problem I can't seem to get around,
here's a small portion of code to recreate the issue
def appendto(array):
temp=[]
for i in range(3):
array.append(i)
temp.append(array)
return temp
array=[]
print(appendto(array))
When I run this code it shows
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
I am trying to make the temp array record each change made to the main array, but by the end it seems to have only recorded the final state of the array 3 times.
The only half - solution I have found is to turn the array into a string before appending it, doing
array.append(str(i))
but this will slow down my program significantly as I will then have to turn the string back into an array in order to use it.
please do tell me if I'm doing something wrong
I think adding a print() statement in your for loop might help illustrate what is going on.
def appendto(array):
temp=[]
for i in range(3):
array.append(i)
temp.append(array)
print(temp)
return temp
array=[]
print(appendto(array))
This will give you:
[[0]]
[[0, 1], [0, 1]]
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
We can see that appending items to array cascades though all references to array. To be clear, there is only one array we just now have a list of three items all pointing to it.
What you probably want to do is append a copy.
def appendto(array):
temp=[]
for i in range(3):
array.append(i)
temp.append(array.copy())
return temp
array=[]
print(appendto(array))
giving you:
[[0], [0, 1], [0, 1, 2]]

Python array sorting with unexpected result [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
def sorted():
print(numList)
sortedList=numList
sortedList.sort()
print(numList)
print(sortedList)
Result:
[4,1,9,16,25]
[1,4,9,16,25]
[1,4,9,16,25]
Actually, I just sort the "sortedList" only, but result shows it sorted numList too. may I know the reason and solution.
You need to make a copy of the list, otherwise it is a pointer to the list and will act on both things.
https://www.programiz.com/python-programming/methods/list/copy
Here's how copy works. You'll want to copy your numList into sortedList and then sort it.
Example:
lst = [0, 1, 2, 3]
lst2 = lst
lst2[0] = 4
lst
>>> [4, 1, 2, 3]
Versus
lst = [0, 1, 2, 3]
lst2 = lst.copy()
lst2[0] = 4
lst
>>> [0, 1, 2, 3]

Replace some None in list without affecting other None [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 4 years ago.
I just met something really strange of Python:
>>> out=[[0]*3]*3
>>> out
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> out[0][1]
0
>>> out[0][1]=9
>>> out
[[0, 9, 0], [0, 9, 0], [0, 9, 0]]
well, obviously, what I want is :
[[0, 9, 0], [0, 0, 0], [0, 0, 0]]
isn't strange? I'm not very familiar with Python, but Python always impresses me with its intuitive behavior. But how it comes up with this?
... and how can I get what I need?
thanks!
Watt
A strange behaviour indeed, but that's only because * operator makes shallow copies, in your case - shallow copies of [0, 0, 0] list. You can use the id() function to make sure that these internal lists are actually the same:
out=[[0]*3]*3
id(out[0])
>>> 140503648365240
id(out[1])
>>> 140503648365240
id(out[2])
>>> 140503648365240
Comprehensions can be used to create different lists as follows:
out = [ [0]*3 for _ in range(3) ]
Using * to duplicate elements in lists is a shallow copy operation, so you will end up with multiple references to the same mutable objects if you use this on a list that contains mutable objects.
Instead, use the following to initialize your nested list:
out = [[0]*3 for _ in range(3)]
You can see that with your method, each entry in out is actually a reference to the same list, which is why you see the behavior that you do:
>>> out = [[0]*3]*3
>>> out[0] is out[1] is out[2]
True

Initializing a two-dimensional array in Python? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 6 years ago.
I wonder What is the difference between this two different method of 2D matrix initialization in python.
m =[]
K = []
for x in range(0,W+1):
m.append(0)
for x in range(0,n+1):
K.append(m)
and
l = []
for j in range(0,n+1):
l.append([])
for i in range(0,W+1):
l[j].append(0))
when I tried to print l and K the both gave the same answer but when I tried to implement it in code the output of program changed.
the earlier one(K) gave an incorrect answer but later one(l) when implemented in the program gave a correct answer.
In the first one, you are storing the same reference to list m in k. Change in m will be reflected in all the reference.
Where as in second, you are creating new lists in l. Hence, change in one is independent of another.
Alternatively, simpler way to initialize list is as:
Holding same reference to list (similar to your first approach) is as:
>>> row, columns = 2, 3
>>> my_list = [[0]*columns]*row
>>> my_list
[[0, 0, 0], [0, 0, 0]]
>>> my_list[0][1] = 1 # changing value
>>> my_list
[[0, 1, 0], [0, 1, 0]]
# ^ ^ Reflected in all
Holding different reference to the list (similar to your second approach) is as:
>>> my_list = [[0]*columns for i in range(row)]
>>> my_list
[[0, 0, 0], [0, 0, 0]]
>>> my_list[0][1] = 1 # changing value
>>> my_list
[[0, 1, 0], [0, 0, 0]]
# ^ only one value is changed

difference between list and array(np)? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 8 years ago.
I was trying add ones to some specific position in a 100*100 zero matrix. My code was something this:
adjacency=[[0]*100]*100
while ...
x=...
y=...
adjacency[x][y]=adjacency[x][y]+1
But it adds to other positions as well. In face, adjacency[0]=adjacency[1]=..=adjacency[99], while there's no way that the calculation of x, y in while-loop will produce this kind of result.
So, I changed to array. The only thing I changed was:
adjacency=np.zeros((100,100))
And the result is right this time. Adjacency[i] no longer equals to each other.
Does anyone know why? (Using Python2.7.)
The * operator is not always a good thing for creating lists, specially multi-dimensional lists. This operator just creates copies of the elements in the list to populate the larger list. This works fine for primitive types, but not for other objects.
For example, when you write [0] * 100, it creates a list of 100 elements and assigns 0 to each item. Now you have the reference of a 100-element list. So when you write [[0] * 100] * 100], you get a list of 100 references of the list [0] * 100. So when you change a value, it affects all the 'rows', because all the rows are referencing the same list.
Here's a smaller example:
>>> a = [0] * 3
>>> print a
[0, 0, 0]
>>> b = [a] * 2
>>> print b
[[0, 0, 0], [0, 0, 0]]
>>> a[0] = 1
>>> print a
[1, 0, 0]
>>> print b
[[1, 0, 0], [1, 0, 0]]
>>> b[0][1] = 2
>>> print b
[[1, 2, 0], [1, 2, 0]]
The first row list is copied every time to the 99 other positions. You need to create a new list for each row, something like this:
adjacency=[[0] * 100 for y in range(100)]

Categories

Resources