How to avoid reference issue with array append in python [duplicate] - python

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 2 years ago.
Let's take the following code
board = [[0,0,0],[0,0,0],[0,0,0]]
versionsOfBoard = []
versionsOfBoard.append(board); #this will keep the versions of board array
print(versionsOfBoard);
# output
# [[[0,0,0],[0,0,0],[0,0,0]]]
# later I change few values in the board and append 'board' to my versions array
board[0][0] = 1
versionsOfBoard.append(board)
print(versionsOfBoard)
# output
# [[[1, 0, 0], [0, 0, 0], [0, 0, 0]], [[1, 0, 0], [0, 0, 0], [0, 0, 0]]]
# if you notice here, the 0th index value is also changed
board[1][2] = 1
versionsOfBoard.append(board)
print(versionsOfBoard)
# output
# [[[1, 0, 0], [0, 0, 1], [0, 0, 0]], [[1, 0, 0], [0, 0, 1], [0, 0, 0]], [[1, 0, 0], [0, 0, 1], [0, 0, 0]]]
Every index value displays the latest state of 'board'. it is referencing the board.
I have tried with .append(board[:]) and .append(board.copy()). Both these options too do not solve the problem.
Any help would be highly appreciated

Try this
import copy
board = [[0,0,0],[0,0,0],[0,0,0]]
versionsOfBoard = []
versionsOfBoard.append(copy.deepcopy(board))
print(versionsOfBoard);
board[0][0] = 1
versionsOfBoard.append(copy.deepcopy(board))
print(versionsOfBoard)
board[1][2] = 1
versionsOfBoard.append(copy.deepcopy(board))
print(versionsOfBoard)

Related

Assigning value in python 2d list [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 12 months ago.
I have previously worked in C, I am facing problem in assigning value in 2d list
graph = [[0]*3]*3
print(graph)
graph[0][1] = 3
print(graph)
Output
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 3, 0], [0, 3, 0], [0, 3, 0]]
Expected output :
[[0, 3, 0], [0, 0, 0], [0, 0, 0]]
Is there any way to assign values other than using numpy array as answered in
Assigning values Python 2D Array
you can use a for loop to do this simply
a = []
for i in range(3):
a.append([0]*3)

Two-Dimention array keeps updating entire row instead of each cell, what's wrong with my code? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
I'm using python to illustrate DP algorithm. During memoization which keeps updating the table, I found that the table was not updated correctly.
I've narrowed down to the line "dp[t_id][_p] = max(choice_1, choice_2)", and I don't see what's the problem there.
tasks = [1,2,2,3]
dp = [[0]*(p+1)]*len(tasks)
for t_id in range(len(dp)):
for _p in range(p+1):
choice_1 = 1
choice_2 = 2
print dp
dp[t_id][_p] = max(choice_1, choice_2)
print dp
I expect the dp table should be updated one cell at a time, whereas dp[0][0] = 2, then dp[0][1] = 2, etc. However, it's updating as dp[every_column][0] = 2. The two prints in code should showcase the issue.
screenshot
dp = [[0]*(p+1)]*len(tasks)
This creates a list of references to the same list. Let's do a simpler example:
dp = [[0] * 5] * 5
dp[0][0] = 42
print(dp)
Output:
[[42, 0, 0, 0, 0], [42, 0, 0, 0, 0], [42, 0, 0, 0, 0], [42, 0, 0, 0, 0], [42, 0, 0, 0, 0]]
As you can see, it looks like the first element of each row is set to 42. This is because each row is the same list. Instead, you need to create several independent lists with a list comprehension or a for loop. For example:
dp = [[0] * 5 for _ in range(6)]
dp[0][0] = 42
print(dp)
Output:
[[42, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Now only the first element of the first row is set.

Python - Create constant array of unique elements [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
I recently tried to instantiate a 4x4 constant (0's) array by using
a = [[0] * 4] * 4
which instantiates the array a as
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
However, this does not create an array of unique elements as altering an element in any of the arrays changes all of them, e.g.:
a[0][0] = 1
alters a to
[[1, 0, 0, 0],
[1, 0, 0, 0],
[1, 0, 0, 0],
[1, 0, 0, 0]]
I think I understand why this happens (copies of lists copy the list's pointer and do not create separate copies unless specified, unlike int's, etc.) but am left wondering:
Is there any quick and easy way to instantiate a constant array (without using any external modules, such as NumPy) with unique elements that can later be altered by simple a[i][j] = x addressing?
a = [[0 for _ in xrange(4)] for _ in xrange(4)]
should do it, it'll create separate lists
Just for free. What is going on here ? When one does
>>> a = [[0] * 4] * 4
first, one creates one list [0] * 4 with four 0 elements. Let call this list li.
Then when you do [li] * 4, one actually creates a list which refers four times to the same object. See
>>> [id(el) for el in a]
[8696976, 8696976, 8696976, 8696976] # in my case
Whence the (not that) curious result one gets when entry-wise assigning like so
>>> a[0][0] = 1
[[1, 0, 0, 0],
[1, 0, 0, 0],
[1, 0, 0, 0],
[1, 0, 0, 0]]
A solution is simply to ensure that each element of the list really is unique. For example doing
#Python2
>>> a = map(lambda _: [0]*4, range(4))
#Python3
>>> a = list(map(lambda _: [0]*4, range(4)))
#Python2&3
>>> a[0][0] = 1
[[1, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]

Creating a Nested List in Python

I'm trying to make a nested list in Python to contain information about points in a video, and I'm having a lot of trouble creating an array for the results to be saved in to. The structure of the list is simple: the top level is a reference to the frame, the next level is a reference to a marker, and the last level is the point of the marker. So for example, the list is setup as such:
markerList # a long list of every marker in every frame
markerList[0] # every marker in the first frame
markerList[0][0] # the first marker of the first frame
markerList[0][0][0] # the x value of the first marker of the first frame
Calling markerList[0] looks like this:
array([[ 922.04443359, 903. ],
[ 987.83850098, 891.38830566],
[ 843.27374268, 891.70471191],
[ 936.38446045, 873.34661865],
[ 965.52880859, 840.44445801],
[ 822.19567871, 834.06298828],
[ 903.48956299, 830.62268066],
[ 938.70031738, 825.71557617],
[ 853.09545898, 824.47247314],
[ 817.84277344, 816.05029297],
[ 1057.91186523, 815.52935791],
[ 833.23632812, 787.48504639],
[ 924.24224854, 755.53997803],
[ 836.07800293, 720.02764893],
[ 937.83880615, 714.11199951],
[ 813.3493042 , 720.30566406],
[ 797.09521484, 705.72729492],
[ 964.31713867, 703.246521 ],
[ 934.9864502 , 697.27099609],
[ 815.1550293 , 688.91473389],
[ 954.94085693, 685.88171387],
[ 797.70239258, 672.35119629],
[ 877.05749512, 659.94250488],
[ 962.24786377, 659.26495361],
[ 843.66131592, 618.83868408],
[ 901.50476074, 585.42541504],
[ 863.41851807, 584.4977417 ]], dtype=float32)
The problem is that every frame contains a different number of markers. I want to create an empty array the same length as markerList (i.e., the same number of frames) in which every element is the same size as the largest frame in markerList. Some important caveats: first,I want to save the results into a .mat file where the final array (which I'll call finalStack) is a cell of cells. Second, I need to be able to reference and assign to any specific part of finalStack. So if I want to move a point to finalStack[0][22], I need to be able to do so without conflict. This basically just means I can't use append methods anywhere, but it's also unearthed my first problem - finding a way to create finalStack that doesn't cause every new assignment to be duplicated throughout the entire parent list. I've tried to do this a few different ways, and none work correctly.
Attempts at a solution:
Following another SO question, I attempted to create finalStack iteratively, but to no avail. I created the following function:
def createFinalStack(numMarkers, numPoints, frames):
step = [[0]*numPoints for x in xrange(numMarkers)]
finalStack = [step]*frames
return finalStack
However, this causes all assignments to be copied across the parent list, such that assigning finalStack[0][12] leads to finalStack[2][12] == finalStack[20][12] == finalStack[0][12]. In this example, numMarkers= 40, numPoints = 2 (just x & y), and frames= 200. (So the final array should be 200 x 40 x 2.)
That said, this seems like the most straightforward way to do what I want, I just can't get past the copy error (I know it's a reference issue, I just don't know how to avoid it in this context).
Another seemingly simple solution would be to copy markerList using copy.deepcopy(markerList), and pad any frames with less than 40 markers to get them to numMarkers = 40, and zero out anything else. But I can't come up with a good way to cycle through all of the frames, add points in the correct format, and then empty out everything else.
If this isn't enough information to work with, I can try to provide greater context and some other not-good-methods that didn't work at all. I've been stuck on this long enough that I'm convinced the solution is horribly simple, and I'm just missing the obvious. I hope you can prove me right!
Thanks!
This illustrates what is going on:
In [1334]: step=[[0]*3 for x in range(3)]
In [1335]: step
Out[1335]: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
In [1336]: stack=[step]*4
In [1337]: stack
Out[1337]:
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
In [1338]: stack[0]
Out[1338]: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
In [1339]: stack[0][2]=3
In [1340]: stack
Out[1340]:
[[[0, 0, 0], [0, 0, 0], 3],
[[0, 0, 0], [0, 0, 0], 3],
[[0, 0, 0], [0, 0, 0], 3],
[[0, 0, 0], [0, 0, 0], 3]]
In [1341]: step
Out[1341]: [[0, 0, 0], [0, 0, 0], 3]
When you use alist*n to create new list, the new list contains multiple pointers to the same underlying object. As a general rule, using *n to replicate a list is dangerous if you plan on changing values later on.
If instead I make an array of the right dimensions I don't have this problem:
In [1342]: np.zeros((4,3,3),int)
Out[1342]:
array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
...
[0, 0, 0]]])
Or in list form:
In [1343]: np.zeros((4,3,3),int).tolist()
Out[1343]:
[[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
If I assign a value in this list, I only change one item:
In [1344]: stack=np.zeros((4,3,3),int).tolist()
In [1345]: stack[0][2]=3
In [1346]: stack
Out[1346]:
[[[0, 0, 0], [0, 0, 0], 3],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
I really should have used stack[0][2][1]=3, but you get the idea. If I make the same assignment in the array form I end up changing a whole row
In [1347]: stack=np.zeros((4,3,3),int)
In [1348]: stack[0][2]=3
In [1349]: stack
Out[1349]:
array([[[0, 0, 0],
[0, 0, 0],
[3, 3, 3]],
[[0, 0, 0],
...
[0, 0, 0]]])
I should have used an expression like stack[0,2,:]=4.
It's probably possible to construct a triply next list like this where all initial values are independent. But this array approach is simpler.

Copying lists: editing copy without changing original [duplicate]

This question already has answers here:
Copying nested lists in Python
(3 answers)
Closed 8 years ago.
I'm making a program that requires and editable temp array that does not affect the original. However, whenever I run the function and test it, it edits the actual array like so:
x = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
y = copying(x)
y[0][0] = 1
print(x)
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
Here is the function:
def copying(array):
temp = []
for i in array:
temp.append(i)
return temp
The function works for flat lists, but the array entry doesn't work. Is there an alternative that I should use? (I have attempted list() and copy())
You need to use the function deepcopy from copy module:
copy.deepcopy(x)
Return a deep copy of x.
This function is copying everything, even sub elements (and sub sub elements and... you understand I think). Your short example corrected:
>>> from copy import deepcopy
>>> x = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> y = deepcopy(x)
>>> y[0][0] = 1
>>> x
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> y
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

Categories