How to initialise a 2D array in Python? - python

I've been given the pseudo-code:
for i= 1 to 3
for j = 1 to 3
board [i] [j] = 0
next j
next i
How would I create this in python?
(The idea is to create a 3 by 3 array with all of the elements set to 0 using a for loop).

If you really want to use for-loops:
>>> board = []
>>> for i in range(3):
... board.append([])
... for j in range(3):
... board[i].append(0)
...
>>> board
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
But Python makes this easier for you:
>>> board = [[0]*3 for _ in range(3)]
>>> board
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

arr=[[0,0,0] for i in range(3)] # create a list with 3 sublists containing [0,0,0]
arr
Out[1]: [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
If you want an list with 5 sublists containing 4 0's:
In [29]: arr=[[0,0,0,0] for i in range(5)]
In [30]: arr
Out[30]:
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
The range specifies how many sublists you want, ranges start at 0, so ranges 4 is 0,1,2,3,4.
gives you five [0,0,0,0]
Using the list comprehension is the same as:
arr=[]
for i in range(5):
arr.append([0,0,0,0])
arr
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]

If you want something closer to your pseudocode:
board = []
for i in range(3):
board.append([])
for j in range(3):
board[i].append(0)

numpy has something for this:
numpy.zeros((3,3))

You can use the style of pseudocode given or simply just use a python one liner
chess_board = [[x]*3 for _ in range(y)] --> list comprehension
or you can use the plain loop style of other languages like java. I prefer the one liner as it looks much nicer and cleaner.

Related

How to get list of lists of decreasing size from n to one

I want for a number n for there to be a nested list containing sublists that start off at length n and decrease to length one. If n was 4, the list would be:
[[0, 0, 0, 0], [0, 0, 0], [0, 0,], [0]]
Here's what I've tried:
triangle = []
for i in range(n):
for k in range(i):
triangle.append(0)
That just gave out for input n = 5:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
If you want to mantain your code form, you just use this function:
def get_triangle_list(n):
triangle_list = []
for i in range(n, 0, -1):
tmp_list = []
for k in range(i):
tmp_list.append(0)
triangle_list.append(tmp_list)
return triangle_list
print(get_triangle_list(4))
and output will be:
[[0, 0, 0, 0], [0, 0, 0], [0, 0], [0]]
But, as suggested by #Abhijit Sarkar, you can obtain the same output in smarter and more efficent way using list comprehension like
triangles = [[0] * x for x in range(n, 0, -1)]
n = 4
triangles = [[0] * x for x in range(n, 0, -1)]
print(triangles)

unable to slice numpy array input [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 11 months ago.
Improve this question
Expected output: [[1,0][1,0]]
Expected output: [[0,0][0,1]]
etc as the loops runs the range.
Error: at print statement. The loop is unable to run through the different indexes.
Error message only integer scalar arrays can be converted to a scalar index
import numpy as np
field = [[1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[1, 0, 1, 0, 0, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 1, 1, 1, 0, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
a2= np.array(field)
print(a2)
for i in list(range(10)):
for i in a2[i:i+2,i:i+2]:
print(a2[i:i+2,i:i+2])
If your goal is to print out a 2 by 2 matrix each time iterating through a2 from left to right and from top to bottom with step 1, the for loops should be like:
for i in range(9):
for j in range(9):
print(a2[i:i+2, j:j+2])
The outputs are:
[[1 0]
[1 0]]
[[0 0]
[0 1]]
[[0 0]
[1 0]]
[[0 0]
[0 0]]
[[0 1]
[0 0]]
etc.
That inside for loop should be for j in a2[i:i+2,i:i+2]: for it to work. it seems like
for i in range(10):
print(a2[i:i+2,i:i+2])
gives the same result
The error is saying that you have used i once then it is not an array to iterate through indexes. Why use two for loops? One for can do the job. Again no need to cast list on range.
for i in range(10):
print(a2[i:i+2,i:i+2])
You could iterate the matrix using a 2x2 window by using the shape of the matrix as a reference and a for loop to slide each dimension (x and y). This is a possible implementation:
for i in range(2, a2.shape[0]):
for j in range(2, a2.shape[1]):
print(a2[i-2:i,j-2:j])
Examine the values during the loops. This is basic python looping logic
In [310]: for i in range(2): # don't need list(range...)
...: print(i)
...: print(a2[i:i+2, i:i+2])
...: for i in a2[i:i+2, i:i+2]:
...: print(i)
...:
...:
0 # outer i
[[1 0] # the a2 window
[1 0]]
[1 0] # inner i, rows of that window
[1 0]
1 # outer i
[[0 1]
[0 1]]
[0 1]
[0 1]
It does not make sense to use the inner i as indices to a2. They are already arrays derived from a2. I don't know why beginners make this mistake
for i in alist:
alist[i] ... # i is an element of the list, not an index
With i being np.array([1,0]), this:
a2[i:i+2,i:i+2]
# a2[np.array([1,0]):np.array([3,2]), ....)
produces your error.
You used the first i in range correctly; why the change in the second?
Using a different iteration variable in the 2nd loop, and range again, produces are more logical nested iteration:
In [313]: for i in range(2):
...: print(i)
...: for j in range(2):
...: print(j)
...: print(a2[i:i+2, j:j+2])

Initialize 2D list

The follow codes didn't behave like I expected. Is this an incorrect way of initializing a 2D list filled with 0?
matrix = [[0] * 4] * 4
for row in matrix:
print(row)
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
matrix[0][0] = 1
for row in matrix:
print(row)
[1, 0, 0, 0]
[1, 0, 0, 0]
[1, 0, 0, 0]
[1, 0, 0, 0]
Use matrix = [[0 for i in range(4)] for j in range(4)] instead of matrix = [[0] * 4] * 4.
matrix = [[0 for i in range(4)] for j in range(4)]
matrix[0][0] = 1
for row in matrix:
print(row)
Output:
[1, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
I actually ran into this problem a while ago! No, this isn't the correct way, at least for what you're expecting to happen.
The problem is that when you initialise this list, you create a list of references back to the first item, so when you modify it, you modify all of them, because in reality they all point to the same object in memory.
Instead of that you can do something like this:
x = 4
y = 4
matrix = [[0]*x for _ in range(y)]
With a result of:
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
Then matrix[0][0] = 1 only sets the first element of the first list to 1.
You can extend this into 3D and beyond by simply adding a new layer of for __ in range(z) on the end and and wrapping it in more square brackets.
That is because the matrix is composed of a copy of the list [0,0,0,0].
This should work:
matrix = [[0 for i in range(4)] for j in range(4)]
matrix[0][0] = 1
In the general case you can make something like numpy.full (but for lists instead of arrays):
def full(shape, fill_value=0):
if len(shape) > 1:
return [full(shape[1:], fill_value) for _ in range(shape[0])]
else:
return [fill_value] * shape[0]
matrix = full((4, 4), 0)

What is wrong with the following program code, attempting to initialize a 4 x 4 matrix of integers?

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

Redundant variable while creating matrix by list comprehension

I am trying to fill up my matrix with zeros. Unfortunatelly, in the following example, variables x and y are redundand:
self.matrix = [[0 for x in range(0, self.N)] for y in range(0, self.N)]
Multiplying list, copy only references what of course is not what I am expecting:
>>> matrix = [[0] * 5] * 5
>>> matrix
[[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]]
>>> matrix[1][1] = "X"
>>> matrix
[[0, 'X', 0, 0, 0], [0, 'X', 0, 0, 0], [0, 'X', 0, 0, 0], [0, 'X', 0, 0, 0], [0, 'X', 0, 0, 0]]
So, is there any solution using a list comprehension to avoid redundand variables (x & y)?
The common idiom is to assign the result to the variable _, which signals a possible reader of your code that the value will not be used:
[[0]*self.N for _ in range(self.N)]
As you see, we can use the [0]*size idiom for the inner list because 0 is an immutable value. Also, you can call range with only one argument, in which case it is treated as the upper bound, with 0 being the lower bound).
If you want, you can build yourself a list build helper that supports creating lists of arbitrary nesting depth:
def make_multi_list(dim, func):
if not dim: return func()
return [make_multi_list(dim[1:], func) for _ in range(dim[0])]
Usage:
>>> make_multi_list((2, 2), lambda: 0)
[[0, 0], [0, 0]]
>>> make_multi_list((3, 2, 1), lambda: 0)
[[[0], [0]], [[0], [0]], [[0], [0]]]
Alternatively, you could do:
from itertools import repeat
self.matrix = [list(repeat(0, self.N)) for _ in range(0, self.N)]

Categories