Changing an element in one list changes multiple lists [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 9 years ago.
I have a list of List say mysolution:
>>>mySolution
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> mySolution[0][0] = 1
>>> mySolution
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
Intended output:
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
why is it that all the 1st elements in my list of list's is being changed to 1?
I would only like to change the first element of the first list to 1.

What matters is how you created your original mysolution list. As it seems, it contains four times the same list which is why changing it once will make it change in all four locations.
To initialize independent zero-filled lists like that, you can do the following:
mysolution = [[0] * 4 for i in range(4)]

It's quite possible that you created the list like this:
mySolution = [0]*4
mySolution = [mySolution]*4
Or equivalently:
mySolution = [[0]*4]*4
Either of the above snippets will create a list with four sublists which are copies of the exact, same sublist, so any modification on one sublist will be reflected on the others - they're one and the same. The solution is to create four different sublists:
mySolution = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Or a bit shorter:
mySolution = [[0]*4 for _ in xrange(4)]

Because all the contained lists are actually the same list. When you do:
l = [0, 0, 0, 0]
my_solution = [l, l, l]
Then, my_solution[0], my_solution[1], and my_solution[2] are references to the same object (l).
If you modify the list in one location, it changes everywhere. That is because lists are mutable objects.
Instead, use multiple lists:
l1 = [0, 0, 0, 0]
l2 = [0, 0, 0, 0]
l3 = [0, 0, 0, 0]
my_solution = [l1, l2, l3]
Which will work as intended.

please note that this is doing fine:
mySolution = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
mySolution[0][0] = 1
print mySolution
>>>
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
it all depends on how you initialized your solution. this
mySolution = [[0, 0, 0, 0]]*4
mySolution[0][0] = 1
print mySolution
gives
>>>
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
>>>
because here each array [0, 0, 0, 0] in mySolution is a copy of initialization array [0, 0, 0, 0] in [[0, 0, 0, 0]]*4. if you change first element of first array, copy of it also change.
with this initialization mySolution = [[0, 0, 0, 0] for x in range(4)] you are not copying the array but appending [0,0,0,0] four times, giving the result that you are expecting.

Related

Number changes in all row of array [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 months ago.
I created a 4x5 2D array using python, and when I wanted to change a number inside it, it automatically changes the number in every row
rows,cols = (4,5)
arr = [[0]*cols]*rows
print (arr)
And this is how the output shows
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
After I created the array, I decide to change a number in the first row
arr[0][2] = 3
print(arr)
But it appears like this
[[0, 0, 3, 0, 0], [0, 0, 3, 0, 0], [0, 0, 3, 0, 0], [0, 0, 3, 0, 0]]
I checked with it and I still can't find any problem in it. May someone help me with it?
'Multiplying' the list copies the value references repeatedly - which is fine for primitives but not so much for lists, like you've seen. If you want different instances of the list, you could use list comprehension:
rows, cols = (4, 5)
arr = [[0] * cols for _ in range(rows)]
arr[0][2] = 3
print(arr) # [[0, 0, 3, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]

Nested array duplication [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 1 year ago.
I'm guessing the problem happens because I append the same array multiple times and any changes made after are made to all the nested arrays. Is there a way to add them to an array and not get that to happen. For what I'm doing I to need about 500 different nested arrays, so doing it manually is a pain.
Output:
Before append
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
after append
[[0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0]]
What I expected to happen after append:
[[0, 0, 0, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Code:
testArray = []
nestedTestArray = []
def testarraynestedcreate():
for countforloop1 in range(4):
nestedTestArray.append(0)
testArray.append(nestedTestArray)
testarraynestedcreate()
print(testArray) # before change
testArray[1][1] = 2 # change element in array
print(testArray) # after change )
You can use copy():
testArray.append(nestedTestArray.copy())
This way each list is independent from each other (and not a reference to the first one).

Python - how to inspect / discover list has references?

One of the more confusing aspects in python is instantiating a list of lists (assuming one isn't using numpy) - for instance, if one tries to do it via simpler multiplication you end up with reference copies:
In [1]: a = [[0] * 4] * 4
In [2]: a
Out[2]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
In [3]: a[0][1] = 1
In [4]: a
Out[4]: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]
As mentioned in various other SO post such as this one, a proper way to instantiate without any references would be as follows:
In [5]: b = [[0 for i in range(4)] for i in range(4)]
In [6]: b
Out[6]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
In [7]: b[0][1] = 1
In [8]: b
Out[8]: [[0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
The question is this - assume one does define their list as done with list a, is there a way to inspect the array in such a way that it will show that it is using references? Merely printing the array will not reveal the references.
Some terminology first: you are talking about lists here (not arrays), which always store references to their elements.
A quick way to check whether all references in a list refer to different objects is
>>> l1 = [[0, 1], [0, 1]]
>>> l2 = [[0, 1]]*2
>>>
>>> len(set(map(id, l1))) == len(l1) # no duplicates
True
>>> len(set(map(id, l2))) == len(l2) # duplicates
False
which simply checks whether there are n unique ids for the objects in a list of length n.
If your list has a very large number of elements, it might be more efficient to do this lazily and return False on the first duplicate id.
def all_unique(lst):
seen = set()
for x in lst:
id_ = id(x)
if id_ in seen:
return False
seen.add(id_)
return True
... works like this:
>>> all_unique(l1)
True
>>> all_unique(l2)
False
You can use the id function:
>>> a = [[0] * 4] * 4
>>> a
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> [id(sublist) for sublist in a]
[1975671202696, 1975671202696, 1975671202696, 1975671202696]
>>> b = [[0 for i in range(4)] for i in range(4)]
>>> b
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> [id(sublist) for sublist in b]
[1975671204808, 1975671205128, 1975671205000, 1975671204872]
As you can see, in a, the ids are all the same, while in b, they are different.

Multiplying a list by a number creates items have relation with the original one? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 9 years ago.
I have a list of List say mysolution:
>>>mySolution
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> mySolution[0][0] = 1
>>> mySolution
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
Intended output:
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
why is it that all the 1st elements in my list of list's is being changed to 1?
I would only like to change the first element of the first list to 1.
What matters is how you created your original mysolution list. As it seems, it contains four times the same list which is why changing it once will make it change in all four locations.
To initialize independent zero-filled lists like that, you can do the following:
mysolution = [[0] * 4 for i in range(4)]
It's quite possible that you created the list like this:
mySolution = [0]*4
mySolution = [mySolution]*4
Or equivalently:
mySolution = [[0]*4]*4
Either of the above snippets will create a list with four sublists which are copies of the exact, same sublist, so any modification on one sublist will be reflected on the others - they're one and the same. The solution is to create four different sublists:
mySolution = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Or a bit shorter:
mySolution = [[0]*4 for _ in xrange(4)]
Because all the contained lists are actually the same list. When you do:
l = [0, 0, 0, 0]
my_solution = [l, l, l]
Then, my_solution[0], my_solution[1], and my_solution[2] are references to the same object (l).
If you modify the list in one location, it changes everywhere. That is because lists are mutable objects.
Instead, use multiple lists:
l1 = [0, 0, 0, 0]
l2 = [0, 0, 0, 0]
l3 = [0, 0, 0, 0]
my_solution = [l1, l2, l3]
Which will work as intended.
please note that this is doing fine:
mySolution = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
mySolution[0][0] = 1
print mySolution
>>>
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
it all depends on how you initialized your solution. this
mySolution = [[0, 0, 0, 0]]*4
mySolution[0][0] = 1
print mySolution
gives
>>>
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
>>>
because here each array [0, 0, 0, 0] in mySolution is a copy of initialization array [0, 0, 0, 0] in [[0, 0, 0, 0]]*4. if you change first element of first array, copy of it also change.
with this initialization mySolution = [[0, 0, 0, 0] for x in range(4)] you are not copying the array but appending [0,0,0,0] four times, giving the result that you are expecting.

Strange behaviour while inserting into spliced lists? [duplicate]

This question already has answers here:
Changing a particular element in a 2-D list in python
(3 answers)
Closed 9 years ago.
What I am trying to achieve is to insert a small 2D-list into a big one (I'm using Python 2.7.3).
Why am I getting different results for var1 and var2?
def modify(foo):
small = [[1]*2]*2
for y, line in enumerate(small):
foo[y+1][1:3] = line
return foo
var1 = [[0]*4]*4
var2 = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
print modify(var1)
print modify(var2)
# Result:
# var1 = [
# [0, 1, 1, 0],
# [0, 1, 1, 0],
# [0, 1, 1, 0],
# [0, 1, 1, 0]]
#
# var2 = [
# [0, 0, 0, 0],
# [0, 1, 1, 0],
# [0, 1, 1, 0],
# [0, 0, 0, 0]]
By using [[0]*4]*4 you are in fact creating a single list ([0]*4) and referencing it four times.
>>> var1 = [[0]*4]*4
>>> var1
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> var1[0][0] = 2
>>> var1
[[2, 0, 0, 0], [2, 0, 0, 0], [2, 0, 0, 0], [2, 0, 0, 0]]
>>> var1[0] is var1[1]
True
It's a little clearer if you replace the inner content with a variable
>> inner = [0]*4
>> var1 = [inner, inner, inner, inner]
>>> var1
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> inner[0] = 1
>>> var1
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
[0]*4 creates [0, 0, 0, 0], however, [[0,0,0,0]]*4 creates a list containing shallow copies of [0,0,0,0]. That means, all inner lists are the same.

Categories