python how to change value of elements of sublists? [duplicate] - python

This question already has answers here:
Creating lists of lists in a pythonic way
(8 answers)
Closed 9 years ago.
I have the following code:
matrix = [[0] * 3] * 3
matrix[0][0] = 2
I want to get the following result:
[[2, 0, 0], [0, 0, 0], [0, 0, 0]]
However it changes the first element of each sublist and returns this list:
[[2, 0, 0], [2, 0, 0], [2, 0, 0]]
If I define matrix as follow:
matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
then it works.
Could anyone tell me please, why it happens and how could solve this problem?
Thanks

This is happening because [[0] * 3] * 3 is actually creating an array of 3 of the same object (the [0] * 3 array). One way of looking at it is that the inner array is created once and copied. An alternative would be to use [[0] * 3 for x in xrange(3)], as this executes [0] * 3 each iteration in list comprehension, creating a new array each time.

Here's your problem, matrix, in this example, is basically identical to:
>>> a = [0,0,0]
>>> matrix1 = [a,a,a]
that means when you do matrix1[0][0] = 2, what Python does is follow its pointer located at the first index of matrix1, which points to object a, then looks at the pointer located at the first index of a, which reads 0, then changes that to 2. Then when you ask it to evaluate matrix1, it looks up a three times and finds [2,0,0] each time.
Sean had a good solution above mine, using list comprehensions to force new objects instead of adding pointers for objects that already exist. That may serve you better :)

Python assigns by pointer rather than value* which sometimes leads to undesirable results such as this one. Here is a tutorial that explains what is really happening: http://www.python-course.eu/variables.php Here is one possible fix http://www.python-course.eu/deep_copy.php
*(as has been pointed out this is not quite right, however it similar in result to what happens in other languages like C which I'm more familiar with if you passed a pointer to a variable rather than a copy of the value of the variable.)

Related

Indexed array filled incorrectly [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 3 years ago.
I just started programming with Python and I have a question concerning 2D arrays.
I need to create a matrix (numpy forbidden) of a certain size from av[1] and save it so that I can multiply it with another one later on.
The logical thing for me was:
1- Get the length of av[1]; 2- Transform the av[1][] to it's ASCII equivalent with ord and finally 3- Insert that value into a list called key_matrix.
The matrix needs to be the smallest size possible and in a "square form", so I calculate the smallest square containing the len of av[1] ( called matrix_size ) and then I initialize my array like this:
key_matrix = [[0] * matrix_size] * matrix_size;
Like that I get my square matrix filled with 0.
If matrix_size = 3 for example I get:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Now the strange part is (and also the part that I'm stuck on) the following, I use
index1 = 0;
index2 = 0;
key_matrix[index1][index2] = ord(sys.argv[1][0]);
print(key_matrix);
to fill only the 1st element of the 1st line.
While the result should be:
[[97, 0, 0], [0, 0, 0], [0, 0, 0]]
I get:
[[97, 0, 0], [97, 0, 0], [97, 0, 0]]
Me and my friends really cant seem to figure out the reason why it does this, any help is welcome!
Thank you all for reading :)
The memory address of the lists are the same when you write [[0] * matrix_size] * matrix_size, it basically reuses the memory address of the first [0] * matrix_size array as the same reference for multiple times for other lists. Since these lists are not independent from memory address perspective, we would have issue modifing only one of the list. You can do below as a quick fix for the issue:
>>> key_matrix2 = [[0] *3 for i in range(matrix_size)]
>>> key_matrix2
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> key_matrix2[0][1] = 2
>>> key_matrix2
[[0, 2, 0], [0, 0, 0], [0, 0, 0]]

How to fix method in python that returns a 2d array with empty array elements?

The following code implements a backtracking algorithm to find all the possible permutations of a given array of numbers and the record variable stores the permutation when the code reaches base case. The code seems to run accordingly, that is, the record variable gets filled up with valid permutations, but for some reason when the method finishes the method returns a two-dimensional array whose elements are empty.
I tried declaring record as a tuple or a dictionary and tried using global and nonlocal variables, but it none of it worked.
def permute(arr):
record = []
def createPermutations(currentArr, optionArr):
if len(optionArr) == 0:
if len(currentArr) != 0: record.append(currentArr)
else: pass
print(record)
else:
for num in range(len(optionArr)):
currentArr.append(optionArr[num])
option = optionArr[0:num] + optionArr[num+1::]
createPermutations(currentArr, option)
currentArr.pop()
createPermutations([], arr)
return record
print(permute([1,2,3]))
The expect result should be [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]], but instead I got [[], [], [], [], [], []].
With recursive functions, you should pass a copy of the current array, rather than having all of those currentArr.pop() mutating the same array.
Replace
createPermutations(currentArr, option)
by
createPermutations(currentArr[:], option)
Finally, as a learning exercise for recursion, something like this is fine, but if you need permutations for a practical programming problem, use itertools:
print([list(p) for p in itertools.permutations([1,2,3])])
I would accept John Coleman's answer as it is the correct way to solve your issue and resolves other bugs that you run into as a result.
The reason you run into this issue because python is pass-by-object-reference, in which copies of lists are not passed in but the actual list itself. What this leads to is another issue in your code; in which you would get [[3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1]] as your output when you print(record).
Why this happens is that when you call record.append(currentArr), it actually points to the same object reference as all the other times you call record.append(currentArr). Thus you will end up with 6 copies of the same array (in this case currentArr) at the end because all your appends point to the same array. A 2d list is just a list of pointers to other lists.
Now that you understand this, it is easier to understand why you get [[],[],[],[],[],[]] as your final output. Because you add to and then pop from currentArr over here currentArr.append(optionArr[num])
and over here
currentArr.pop() to return it back to normal,
your final version of currentArr will be what you passed in, i.e. [].
Since result is a 2d array of 6 currentArrs, you will get [[],[],[],[],[],[]] as your returned value.
This may help you better how it all works, since it has diagrams as well: https://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/

How does this Python's list value assignment works in this case? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 3 years ago.
I have come across a strange behaviour in Python's value assignment. If I create a list such as List =[[0, 0], [0, 0]] and want to change a value indexed 1 in the list indexed as 1 I simply use: List[1][1] = 1. However, this is not a case of the code below. Eventhough the list seems same as the one mentioned above, it assigns more values then I expect. Is there anyone who can explain how this work?
size = 2
matrix = [[]]
for j in range(size):
matrix[0].append(0)
for i in range(size-1):
matrix.append(matrix[0])
matrix[1][1] = 1
print(str(matrix))
I would expect the output as [[0, 0], [0, 1]], but the actual output is [[0, 1], [0, 1]]. Why is the value at position matrix[0][1] assigned as 1??
When you do:
matrix.append(matrix[0])
You're appending to matrix the reference to the object matrix[0] (which is a list), it isn't creating a new list.

Indexing of lists within a list in python [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Python list multiplication: [[...]]*3 makes 3 lists which mirror each other when modified [duplicate]
(4 answers)
Closed 6 years ago.
I have a list of lists in python.
z=[[0]*6]*7
Since all elements are 0. But now if i want to change an individual element within a list e.g
z[0][0]=2
This should change the first element of the first list. But it actually changes the first element of all elements. This is so illogical to me.
Can some one help.
[2, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0],
[2, 0, 0, 0, 0, 0]]
That's a classical "programmer's trap" in python.
l = [ 0 ] * 6
creates a list containing six times a reference to the same python object, here, the numerical constant 0.
Now, setting
l[0] = 1
will replace the first reference to the const 0 object by a reference to another object, the const 1 object.
Now, let's look at
z=[[0]*6]*7
This first creates a list containing six references to the const 0 object, and then it creates a list containing seven references to that single six-element list.
Now,
z[0]
will give you the first element from z, which is simply the same as all the six other elements.
Proof:
print id(z[0]) == id(z[1])
different objects have different IDs.
So you never actually made a list of different lists, but just the same list all over.
You can actually create different sublists and put them into one by doing something like
z = [ [0]*6 for _ in range(7) ]
However, I get the feeling you actually might want to use matrices – if that's really the case, numpy's ndarray is what you're after, because:
import numpy
z = numpy.ndarray((7,6))
actually gives you a matrix with 42 numeric elements.

Python multiple dimension arrays [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to initialize a two-dimensional array in Python?
In solving a simple problem regarding a two dimensional array I came across a solution on this site that explained how to declare one in Python using the overload operator.
Example:
Myarray = [[0]*3]*3
this would produce the following array (list)
[[0,0,0],[0,0,0],[0,0,0]]
This seems fine until you use it:
if you assign an element for example:
Myarray [0][0] = 1
you get the unexpected output:
[[1,0, 0],[1,0,0] , [1,0,0]]
In effect assigning Myarray [1][0] and Myarray[2][0] at the same time
My solution:
Myarray = [[][][]]
for i in range(0,3):
for j in range (0,3):
Myarray[i].append(0)
This solution works as intended:
Marray[0][1] = 1
gives you
[[1,0, 0],[0,0,0] , [0,0,0]]
Is there a simpler way to do this? This was a solution to an A level Cambridge question and seems too long winded for students compared to other languages.
With vanilla Python, you could use this, a nested list comprehension
>>> m = [[0 for y in range(3)] for x in range(3)]
>>> m
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Unlike the multiplied list you showed in your example, it has the desired behavior
>>> m[1][0] = 99
>>> m
[[0, 0, 0], [99, 0, 0], [0, 0, 0]]
However, for serious use of multidimensional arrays and/or numerical programming, I'd suggest you use Numpy arrays.

Categories

Resources