unable to slice numpy array input [closed] - python

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

Related

Replace all but the first 1 in an array with 0

I am trying to find a way to replace all of the duplicate 1 with 0. As an example:
[[0,1,0,1,0],
[1,0,0,1,0],
[1,1,1,0,1]]
Should become:
[[0,1,0,0,0],
[1,0,0,0,0],
[1,0,0,0,0]]
I found a similar problem, however the solution does not seem to work numpy: setting duplicate values in a row to 0
Assume array contains only zeros and ones, you can find the max value per row using numpy.argmax and then use advanced indexing to reassign the values on the index to a zeros array.
arr = np.array([[0,1,0,1,0],
[1,0,0,1,0],
[1,1,1,0,1]])
res = np.zeros_like(arr)
idx = (np.arange(len(res)), np.argmax(arr, axis=1))
res[idx] = arr[idx]
res
array([[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0]])
Try looping through each row of the grid
In each row, find all the 1s. In particular you want their indices (positions within the row). You can do this with a list comprehension and enumerate, which automatically gives an index for each element.
Then, still within that row, go through every 1 except for the first, and set it to zero.
grid = [[0, 1, 0, 1, 0], [1, 0, 0, 1, 0], [1, 1, 1, 0, 1]]
for row in grid:
ones = [i for i, element in enumerate(row) if element==1]
for i in ones[1:]:
row[i] = 0
print(grid)
Gives: [[0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0]]
You can use cumsum:
(arr.cumsum(axis=1).cumsum(axis=1) == 1) * 1
this will create a cummulative sum, by then checking if a value is 1 you can find the first 1s

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)

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.

How to initialise a 2D array in 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.

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

Categories