Why I can't make a two dimensional array with this code? - python

I was trying to solve a problem but I encounter a problem.
When I do this:
arr=[[[0]*5]*5]
I get this:
[[[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]]]
But when I try to select an element:
arr[0][0]
It returns this:
[0, 0, 0, 0, 0]
Why?

Simply remove the outer []:
arr=[[0]*5]*5
However that's a bad way to create nested lists. It's better to use:
arr = [[0 for _ in range(5)] for _ in range(5)]
That way you don't get bitten by the "shared reference problem".

arr = [[0]*5]*5 #will work
so arr = [[[0]*5]*5] is equivalent to arr = [your required arr] inside another list

You have an extra pair of square brackets. Try arr = [[0]*5]*5.

You have an extra pair of brackets.
Try instead:
arr = [[0] * 5] * 5
We can prove this by breaking down your code:
arr= [ [ [ 0 ] * 5 ] * 5]
We condense the innermost layer to be: arr = [ [ [0]*5 ] * 5] which returns:
[ [[0, 0, 0, 0, 0]] * 5]
Now the inner portion returns:
[[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]]
As your desired result is now present, we now see that the remaining brackets are no longer needed.

because you're not getting
[[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]]
you're getting
[[[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]]]
omit the extra brackets.
arr=[[0]*5]*5

Related

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

Apending a list in a list multiple times retaining the ability to change a specific element in python

I want to create a grid with a variable number of rows and columns. What I have done to achieve this is this
BaseRow = []
for j in range (0, columns):
BaseRow.append(0)
Grid = []
for j in range (0, rows):
Grid.append(BaseRow)
So all seems fine until now, I print the rows in order with this piece of code
for i in range (1, rows+1):
print Grid[rows-i]
and a grid that looks something like this
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
is printed. Thing is, afterwards, I want to change a specific element. But when I do,
Grid[0][0] = 1
and print again, instead of just changing the rightmost down most 0 to a 1, the whole column changes, so it becomes
[1, 0, 0]
[1, 0, 0]
[1, 0, 0]
I suspect it sees that Grid is taking from BaseRow, so it changes BaseRow, and then the Grid takes the rows from BaseRow and just puts that value everywhere. I suspect .append might not be what I am looking for, but for all the research I have done I have not managed to find something else to use. If I understand correctly, .extend will not add it as a list but as individual numbers. What should I change, or how should I structure this?
Please excuse my limited knowledge, I just started programming in python half a week ago. Thanks for your help!
BaseRow = []
for j in range (0, columns):
BaseRow.append(0)
Grid = []
for j in range (0, rows):
Grid.append(BaseRow)
When you do this, the same instance of BaseRow is appended to Grid multiple times. So, if you change even row in Grid, the effect will be on all rows, as it is basically the same instance of list in all rows.
If you want a copy of BaseRow to be appended to Grid, use the below code:
for j in range(0, rows):
Grid.append(BaseRow[:])
You could also use list comprehension:
Grid = [[0 for j in range(0, columns)] for i in range(0, rows)]
Output for Columns = 3 and rows = 4:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Output after setting Grid[0][0] = 1:
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
If you ask me, I would any day use List comprehension because it's so clean and easy:
columns, rows = 3, 3
lst = [[0 for j in range(columns)] for i in range(rows)] # List of List with 3 Columns and 3 Rows
lst[0][0] = 1 # modifying a member
print (lst) # Print the result
# Result: [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
I personally prefer list comprehension but your code needs just little changes and it will serve you well. You append list and to that list you append elements:
matrix = []
for i in range(3):
matrix.append([])
for j in range(4):
matrix[-1].append(0)
print(matrix)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
matrix[0][0] = 1
print(matrix)
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

How can I change an element inside my two dimensional array in python?

This is how I've created my two dimensional array:
matrix = [[0 for x in range(5)] for x in range(3)]
print(matrix)
Running this code returns this:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
However I want to write a function where I can ask for an input and substitute a zero in a specific place with the input. I want a way of telling the computer which zero to substitute with the input the user will give.
You simply use two pairs of square brackets ([]):
matrix = [[0 for x in range(5)] for x in range(3)]
def my_function(input, idx1, idx2):
matrix[idx1][idx2] = input
As you'd expect the first pair of square brackets ([]) correspond to the outer list and the second pair of square brackets correspond to the inner list.
def f(matrix, idx1, idx2, value):
matrix[idx1][idx2] = value
test:
>>> matrix = [[0 for x in range(5)] for x in range(3)]
>>> def f(matrix, idx1, idx2, value):
... matrix[idx1][idx2] = value
...
>>> f(matrix, 2, 4, -99)
>>> matrix
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, -99]]
Perhaps this helps to see what is going on
>>> matrix[2]
[0, 0, 0, 0, -99] # 3rd item of matrix
>>> matrix[2][4]
-99 # 5th item of matrix[2]
Remember that indices start at 0

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

Python multi-dimensional array initialization without a loop

Is there a way in Python to initialize a multi-dimensional array / list without using a loop?
Sure there is a way
arr = eval(`[[0]*5]*10`)
or
arr = eval(("[[0]*5]+"*10)[:-1])
but it's horrible and wasteful, so everyone uses loops (usually list comprehensions) or numpy
Depending on your real needs, the de facto "standard" package Numpy might provide you with exactly what you need.
You can for instance create a multi-dimensional array with
numpy.empty((10, 4, 100)) # 3D array
(initialized with arbitrary values) or create the same arrays with zeros everywhere with
numpy.zeros((10, 4, 100))
Numpy is very fast, for array operations.
The following does not use any special library, nor eval:
arr = [[0]*5 for x in range(6)]
and it doesn't create duplicated references:
>>> arr[1][1] = 2
>>> arr
[[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]]
Sure, you can just do
mylist = [
[1,2,3],
[4,5,6],
[7,8,9]
]
I don't believe it's possible.
You can do something like this:
>>> a = [[0] * 5] * 5
to create a 5x5 matrix, but it is repeated objects (which you don't want). For example:
>>> a[1][2] = 1
[[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]]
You almost certainly need to use some kind of loop as in:
[[0 for y in range(5)] for x in range(5)]
Recursion is your friend :D
It's a pretty naive implementation but it works!
dim = [2, 2, 2]
def get_array(level, dimension):
if( level != len(dimension) ):
return [get_array(level+1, dimension) for i in range(dimension[level])]
else:
return 0
print get_array(0, dim)
It depends on what you what to initialize the array to, but sure. You can use a list comprehension to create a 5×3 array, for instance:
>>> [[0 for x in range(3)] for y in range(5)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> [[3*y+x for x in range(3)] for y in range(5)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14]]
Yes, I suppose this still has loops—but it's all done in one line, which I presume is the intended meaning of your question?
a = [[]]
a.append([1,2])
a.append([2,3])
Then
>>> a
[[1, 2], [2, 3]]
If you're doing numerical work using Numpy, something like
x = numpy.zeros ((m,n))
x = numpy.ones ((m,n))
Python does not have arrays. It has other sequence types ranging from lists to dictionaries without forgetting sets - the right one depends on your specific needs.
Assuming your "array" is actually a list, and "initialize" means allocate a list of lists of NxM elements, you can (pseudocode):
for N times: for M times: add an element
for N times: add a row of M elements
write the whole thing out
You say you don't want to loop and that rules out the first two points, but why?
You also say you don't want to write the thing down (in response to JacobM), so how would you exactly do that? I don't know of any other way of getting a data structure without either generating it in smaller pieces (looping) or explicitly writing it down - in any programming language.
Also keep in mind that a initialized but empty list is no better than no list, unless you put data into it. And you don't need to initialize it before putting data...
If this isn't a theoretical exercise, you're probably asking the wrong question. I suggest that you explain what do you need to do with that array.
You can do by this way:
First without using any loop:
[[0] * n] * m
Secondly using simple inline list comprehension:
[[0 for column in range(n)] for row in range(m)]
You can use N-dimensional array (ndarray). Here is the link to the documentation. http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html

Categories

Resources