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]]
Related
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 2 months ago.
Input = 5
GM1 = [0 for x in range(Input)]
GameBoard = [GM1 for x in range(Input)]
print(*GameBoard, sep="\n")
GameBoard[1][1] = 5
print(*GameBoard, sep="\n")
ok so in the final print statement, I expect this result:
[0, 0, 0, 0, 0]
[0, 5, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
but instead, I'm getting
[0, 5, 0, 0, 0]
[0, 5, 0, 0, 0]
[0, 5, 0, 0, 0]
[0, 5, 0, 0, 0]
[0, 5, 0, 0, 0]
Why is this happening and how can I solve this?
I think the problem is about list comprehension I used.
Try this:
GameBoard = [GM1.copy() for x in range(Input)]
And this article will help you to understand what's going on:
Immutable vs Mutable types
and how can I solve this?
it's quite easy:
GameBoard = [[0]*Input for _ in range(Input)]
The problem is not the list comprehension, but something that is called aliasing. In your case, this means that GameBoard is actually referencing the same object 'GM1' five times.
When you modify one item in a row of GameBoard, you are actually modifying the item at index 1 of the GM1 list, which is shared by all of the rows of GameBoard. Since GM1 is used as the rows of GameBoard, this means that the change is applied to all of the rows of GameBoard.
This issue can be avoided by making a copy of GM1, instead of a direct reference, as iYasha pointed out in their answer:
GameBoard = [GM1.copy() for x in range(Input)]
Each row will then be a separate list, so modifying one item in the list will not affect the other rows (lists).
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.
Create a two-dimensional array named A with ROWS rows and COLS columns. ROWS and COLSS are specified by the user at run time. Fill A with randomly-chosen integers from the range [ -10,99 ], then repeatedly perform the following steps until end-of-file(1) input an integer x(2) search for x in A(3) when x is found in A, output the coordinate (row,col) where x is found, otherwise output the message "x not found!"
I need help I am wondering how can we define two-dimensional array named A with ROWS rows and COLS columns. ROWS and COLSS are specified by the user at runtime in python latest version
#--------------------------------------
#Hw 7
#E80
#---------------------------------------
A = [[Rows],[ColSS]] #I really dont know how to defend this part
for i in range (-10,99): #dont worry about this its just the logic not the actual code
x = int(input("Enter a number : "))
if x is found in A
coordinate row and clumn
otherwise output "x is not found"
The idiomatic way to create a 2D array in Python is:
rows,cols = 5,10
A = [[0]*cols for _ in range(rows)]
Explanation:
>>> A = [0] * 5 # Multiplication on a list creates a new list with duplicated entries.
>>> A
[0, 0, 0, 0, 0]
>>> A = [[0] * 5 for _ in range(2)] # Create multiple lists, in a list, using a comprehension.
>>> A
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> A[0][0] = 1
>>> A
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Note you do not want to create duplicate lists of lists. It duplicates the list references so you have multiple references to the same list:
>>> A = [[0] * 5] * 2
>>> A
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> A[0][0] = 1
>>> A
[[1, 0, 0, 0, 0], [1, 0, 0, 0, 0]] # both rows changed!
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]]
What is wrong with the following program code, attempting to initialize a 4 x 4 matrix of integers? How should the initialization be done?
line = [0] * 4
matrix = [line, line, line, line]
Use a list comprehension:
>>> line = [[0]*4 for _ in xrange(4)]
>>> line
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Don't do this though:
>>> line = [[0]*4]*4
>>> line
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
The output looks same, but the problem here is all inner lists are actually the same object repeated 4 times:
>>> [id(x) for x in line]
[156931756, 156931756, 156931756, 156931756]
So, changing one of them is going to affect all:
>>> line[2][0] = 10
>>> line
[[10, 0, 0, 0], [10, 0, 0, 0], [10, 0, 0, 0], [10, 0, 0, 0]]
Same thing is applicable to your code:
>>> line = [0] * 4
>>> matrix = [line, line, line, line]
>>> [id(x) for x in matrix]
[158521804, 158521804, 158521804, 158521804]
If line contains only immutable object then you can change your code do:
>>> matrix = [line[:] for _ in xrange(4)]
But, if line contains mutable objects itself, then you'd have to use either copy.deepcopy or better create a new line object inside the list comprehension.
you could use numpy for that if you want to perform computations on your matrix
import numpy as np
zeros = np.zeros([4,4])
The problem is:
>>> line = [0] * 4
>>> matrix = [line, line, line, line]
>>> matrix[0][0] = 5
>>> matrix
[[5, 0, 0, 0], [5, 0, 0, 0], [5, 0, 0, 0], [5, 0, 0, 0]]
You have and array of references to the same vector.
What is wrong here that you create a list of 4 references to line list. If you change any of sub-lists or line itself, you affect all sub-lists of matrix, since they (sub-lists) are essentially the same list
Here is a little demonstration
In [108]: line = [0] * 4
In [109]: matrix = [line, line, line, line]
In [110]: line[1]=2
In [111]: matrix
Out[111]: [[0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0], [0, 2, 0, 0]]
In [112]: matrix[1][3] = 4
In [113]: matrix
Out[113]: [[0, 2, 0, 4], [0, 2, 0, 4], [0, 2, 0, 4], [0, 2, 0, 4]]
In [114]: for row in matrix:
.....: print id(row)
.....:
3065415660
3065415660
3065415660
3065415660
You need to do this:
matrix = [[0 for row in range(4)] for col in range(4)]
Your code works ok, but it's not flexible one. So, if you want to create 5*5 martix you have explicitly add more line objects to matrix init code. So, using for + xrange generators looks more suitable.
Also, not sure about case of using this matrix - but be aware about using the same object (list) as matrix line. So, if you change it's element - it would be modified in all rows:
matrix[0][0] = 'new value'
print matrix
[['new value', 0, 0, 0], ['new value', 0, 0, 0], ['new value', 0, 0, 0], ['new value', 0, 0, 0]]