Constructing a two-dimensional list [duplicate] - python

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Unexpected feature in a Python list of lists
I tried to create a list in python using following statement
S = [0] * 10
And it worked out well
S[0] = 1
S
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But when I try to generate a two-dimensional list, something unexpected occurs
S = [[0] * 10] * 2
S[0][1] = 1
S[0][2] = 2
S
[[0, 1, 2, 0, 0, 0, 0, 0, 0, 0], [0, 1, 2, 0, 0, 0, 0, 0, 0, 0]]
Note that S[0] == S[1]
Why?
By the way, is this the best approach of constructing an 2d array? If not, what makes the best?

Because you told it to make 2 copies of the same mutable list.
S = [[0] * 10 for x in range(2)]

S = [[0] * 10] * 2 means 2 references for [[0]*10], so when your change one the other will change.By the way ,the reason why [0]*10 is fine is : a reference to a number.

Related

Why is this happening when I'm trying to change an index from a list? [duplicate]

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).

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]]

Multiply arrays to make matrix gives unexpected result [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 8 years ago.
Suppose I have this code:
dim = 3
eye = [[0] * dim] * dim
and it is a list of list, I checked
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Now, if I do this, I get:
eye[1][2] = 1
eye
[[0, 0, 1], [0, 0, 1], [0, 0, 1]]
However, if I manually put in this expression, the above code works as expected:
eye2=[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
eye2[1][2] = 1
eye2
[[0, 0, 0], [0, 0, 1], [0, 0, 0]]
What is the difference between the two ?
Update: Thanks for all the explanations, suppose I have this code:
a = [0]
type(a)
b = a * 3 # or b = [[0] *3]
So, b holds the 3 references to a. And I expect changing b[0] or b[1] or b[2] will change all 3 elements.
But this code shows the normal behavior, why is that ?
b[1] = 3
b
[0, 3, 0]
Any array entry is as a label of memory address and when you multiple it with a variable actually you create a pointer to 3 palace in your array ! you can figure it out with a list comprehension as below :
Matrix = [[0 for x in xrange(3)] for x in xrange(3)]
dim = 3
eye = [[0] * dim] * dim
its make the copy of same, of if you change at one place it will be reflected to all
dim = 3
eye = [[0] * dim] * dim
print id(eye[0])
print id(eye[1])
print id(eye[2])
Ouput:-
139834251065392
139834251065392
139834251065392
So when you are doing eye = [[0] * dim] * dim it actually refrencing
refrencing three list to same object that is eye.
while in other case
eye2=[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
print id(eye2[1])
print id(eye2[2])
print id(eye2[0])
ouput:-
139863345170480
139863260058256
139863260067240
Here everytime refrence id is diffrent.

How to quickly count number of 0(s) in a binary list? [duplicate]

This question already has answers here:
How do I count the occurrences of a list item?
(30 answers)
Closed 9 years ago.
With an array like [0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0], is there a quick way to return the number of 0(s), which is 5 in the example? Thanks!
Use list.count:
your_list.count(0)
And the help:
>>> help(list.count)
Help on method_descriptor:
count(...)
L.count(value) -> integer -- return number of occurrences of value
li = [0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0]
print len(li) - sum(li)
In [16]: l = [0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0]
In [17]: l.count(0)
Out[17]: 5
Your choice, whatever lets you sleep at night:
l = [0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0]
print l.count(0)
# or maybe:
print len(filter(lambda a: a == 0, l))
# or maybe:
print len([0 for x in l if x==0])
You can speed things up by a factor of 100 by using arrays (, which only becomes important for large lists)...
This should be 100 times faster than my_list.count(0):
(my_array==0).sum()
However it only helps, if your data is already arranged as a numpy array (or you can manage to put it into a numpy array when it is created). Otherwise the conversion my_array = np.array(my_list) eats the time.

Categories