Initialise matrix in python [duplicate] - python

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Python list problem
I try to initialise a matrix in python.
First I did this:
>>> M=[[0]*4]*4
But here is my probleme, every line is changing when I change the first one:
>>> M
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> M[1][1]=1
>>> M
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]
So I did it this way:
>>> M= [ [ 0 for i in range(4) ] for j in range(4) ]
And ut works fine:
>>> M
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> M[1][1]=1
>>> M
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
My question is:
What these two expressions really mean ? ans why the first one is behaving this way ?
Thanks in advance for you help.

When you multiply those lists, Python is copying them by reference rather than creating entirely new objects.
A simple example might help, showing what happens with copy by reference:
>>> pie = ['apple', 'cherry', 'pecan']
>>> pie_copy = pie
>>> pie_copy[0] = 'banana'
>>> pie
['banana', 'cherry', 'pecan']
>>> pie is pie_copy
True
>>> new_pie = ['banana', 'cherry', 'pecan']
>>> pie is new_pie
False
In the same way that pie_copy and pie point to the same list, when building lists by multiplying, all the copies point to the same list.
In your second snippet using range() and list comprehensions, you aren't taking a single list and copying it several times; each iteration in the comprehension is creating a new list, so you don't suffer from the same copy by reference problem.

Because here M=[[0]*4]*4
You create a links on objects.
It's the similar as
>>> a = [0, 0, 0]
>>> b = [a,a,a]
>>> b
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> a[1] = 1
>>> b
[[0, 1, 0], [0, 1, 0], [0, 1, 0]]
>>>
UPD links I meant references, sorry if little confusing

Say a is some python object. Then [a] * 4 is equivalent to [a, a, a, a]. What this means depends on whether a is mutable or not. Numbers, strings and tuples are not, so if a is one of these kinds of objects (0 in your example), then you get 4 independently changeable copies. Lists, dictionaries and sets are mutable, and in this case you just get 4 references to the same object, in your case the list [0] * 4. Exploiting this knowledge, you'll see that you can do this:
M = [[0] * 4 for i in range(4)]
and get what you want.

Related

Python: Nested List is not replacing values correctly [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 1 year ago.
I have a nested list containing nothing but 0's, defined by a size of 5 by 5, and I want to be able to set specific values int he nested list to 1 using direct indexing. This is the solution I currently have:
Grid = [[0] * 5] * 5
ObX = 2
print(ObX)
ObY = 3
print(ObY)
Grid[ObY][ObX] = 1
print(Grid)
Expected output:
2
3
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0]]
Actual Output:
2
3
[[0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]]
As far as I can tell, it's ignoring the "ObY" index and just deciding that it wants to replace every value in each list at index "ObX". What am I doing wrong?
The list of lists you created contains the same list 5 times, changing it once changes all of its copies
In [1]: Grid = [[0] * 5] * 5
In [2]: [id(x) for x in Grid]
Out[2]:
[140392398718848,
140392398718848,
140392398718848,
140392398718848,
140392398718848]
Use this to create 5 different lists
In [5]: Grid =[[0]*5 for _ in range(5)]
In [6]: [id(x) for x in Grid]
Out[6]:
[140392397938112,
140392396267776,
140392397478656,
140392398276224,
140392398427200]

Issue while modifying elements of nested list in Python

In this code, I was expecting that list A will have the same value even if I assign it to another temp variable and then print the argument A using the function foo. However, if A was a scalar e.g. A=3 then the value of A remains the same even after calling foo.
Where am I going wrong? Is there a problem in the scope of variables? I found some related Strange behavior of lists in python answer but couldn't figure out a fix for my problem.
A = [ [ 0 for i in range(3) ] for j in range(3) ]
def foo(input):
temp= input
temp[0][0]=12
print(input)
print(A)
answer = foo(A)
Output:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[12, 0, 0], [0, 0, 0], [0, 0, 0]]
instead of input, use the .copy this will make a copy of the array and assign new addresses to temp, what you do is shallow copying, where temp = input, just copies the address of the input array to temp, rather than making a copy of the list.
So you may either do foo(A.copy()) or temp=input.copy() also note input is not a good name since it is already assigned to a python function, use something like foo_arg or something
Please this, I used deepcopy
from copy import copy, deepcopy
A = [ [ 0 for i in range(3) ] for j in range(3) ]
def foo(input):
temp = deepcopy(input)
temp[0][0]=12
return temp
print('origin', A)
answer = foo(A)
print('after', A)
print('result', answer)
Result:
origin [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
after [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
result [[12, 0, 0], [0, 0, 0], [0, 0, 0]]

Insert value into the element of 2D array

Supposed I created the 2D array of 3x4 with zeros initialization.
Then, I want to add 100 into arr[0][1] and I expect that 100 is added Only into arr[0][1] cell. Refer to Case 1 and Case 2:
From Case 1:
what I saw is that 100 is added into every row with column 1 of arr. It is not what i expected.
From Case 2
The result is what i have expected. Can anyone help me explain?
Case 1:
>>> arr = [[0]*4]*3
>>> arr
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> len(arr)
3
>>> len(arr[0])
4
>>> type(arr)
<class 'list'>
>>> arr[0] [1] = 100
>>> arr
[[0, 100, 0, 0], [0, 100, 0, 0], [0, 100, 0, 0]]
Case 2:
>>> arr = [[0]*4 for _ in range(3)]
>>> arr
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> type(arr)
<class 'list'>
>>> arr[0] [1] = 100
>>> arr
[[0, 100, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[0]*4 creates a list of references to the same object 0. Since integers are immutable, that's OK; changing one element replaces it with a new object. However, [[0]*4]*3] creates a list with 3 references to the same, mutable list object that contains 4 references to 0. Changing an element of one list, as you've seen, shows up as a change in all 3 references.
In the list comprehension, a new list [0]*4 is created for each value of _, rather than simply storing a new reference to the same list.

Inserting a value to a sublist in a list. PYTHON

This piece of code is from a tic tac toe game I am making. I have to insert a value into a sublist in a list. This is my attempt at doing just that, but it does not work (Python 3.5.1). Is it possible to use insert() to insert a value into a sublist, if so, how do you do it?
game_board_lst = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
play1_row = int(input("Player 1: What row? "))
play1_col = int(input("Player 1: What column? "))
game_board_lst.insert((play1_row - 1)(play1_col - 1), 1)
Use the subscript operator lst[index].
Since you have a list of lists, you would use lst[row][col]:
>>> game_board_lst = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> game_board_lst[1][1]=3
>>> game_board_lst
[[0, 0, 0], [0, 3, 0], [0, 0, 0]]
Based on your example, I think you would want to modify an existing value, such as:
game_board_lst[play1_row-1][play1_col-1] = 1

Nested List Indices [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 9 years ago.
I have experienced some problem by using a nested list in Python in the code shown bleow.
Basically, I have a 2D list contains all 0 values, I want to update the list value in a loop.
However, Python does not produce the result I want. Is there something that I misunderstand about range() and Python list indices?
some_list = 4 * [(4 * [0])]
for i in range(3):
for j in range(3):
some_list[i+1][j+1] = 1
for i in range(4):
print(some_list[i])
The results I expected are:
[0, 0, 0, 0]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]
But the actual results from Python are:
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]
What's going on here?
The problem is caused by the fact that python chooses to pass lists around by reference.
Normally variables are passed "by value", so they operate independently:
>>> a = 1
>>> b = a
>>> a = 2
>>> print b
1
But since lists might get pretty large, rather than shifting the whole list around memory, Python chooses to just use a reference ('pointer' in C terms). If you assign one to another variable, you assign just the reference to it. This means that you can have two variables pointing to the same list in memory:
>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]
So, in your first line of code you have 4 * [0]. Now [0] is a pointer to the value 0 in memory, and when you multiply it, you get four pointers to the same place in memory. BUT when you change one of the values then Python knows that the pointer needs to change to point to the new value:
>>> a = 4 * [0]
>>> a
[0, 0, 0, 0]
>>> [id(v) for v in a]
[33302480, 33302480, 33302480, 33302480]
>>> a[0] = 1
>>> a
[1, 0, 0, 0]
The problem comes when you multiply this list - you get four copies of the list pointer. Now when you change one of the values in one list, all four change together:
>>> a[0][0] = 1
>>> a
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
The solution is to avoid the second multiplication. A loop does the job:
>>> some_list = [(4 * [0]) for _ in range(4)]
Actually all the objects in your list are same, so changing one changes others too:
In [151]: some_list = 4 * [(4 * [0])]
In [152]: [id(x) for x in some_list]
Out[152]: [148641452, 148641452, 148641452, 148641452]
In [160]: some_list[0][1]=5 #you think you changed the list at index 0 here
In [161]: some_list
Out[161]: [[0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0]] #but all lists are changed
Create your list this way:
In [156]: some_list=[[0]*4 for _ in range(4)]
In [157]: some_list
Out[157]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
In [158]: [id(x) for x in some_list]
Out[158]: [148255436, 148695180, 148258380, 148255852]
In [163]: some_list[0][1]=5
In [164]: some_list
Out[164]: [[0, 5, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] #works fine in this case

Categories

Resources