0

I'm trying to get the index of elements in a row that is filled.

I tried to use numpy where() function, but it's only returning the index of non-zero elements.

import numpy as np
board = np.array([[0, 0, 0, 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, 0, 0, 0],
                  [2, 2, 2, 2],
                  [0, 0, 0, 0]])
for rows in board:
    if set(rows) == {2}:
        if len(set(rows)) <= 1:
            print(np.where(board == rows))

My desired output is the following:

(array([9, 9, 9, 9], dtype=int32), array([0, 1, 2, 3], dtype=int32)) 

that is, row, col.

However, I'm getting this instead:

(array([2, 9, 9, 9, 9], dtype=int32), array([1, 0, 1, 2, 3], dtype=int32)) 

As stated above, it should only get the index of elements in a filled row. The board1 is not filled with 2's, yet it's being included.

Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
Cast Fellow
  • 63
  • 2
  • 11
  • What's the expected o/p? – Divakar Jun 30 '17 at 14:43
  • Your question is not quite clear. Would you please provide a sample of your desired output given the `board` array you listed in your question? – yifan Jun 30 '17 at 14:50
  • You actually don't need the second `if`, because `set(rows) == {2}` will only return `True` if the sets are equal, and the second row is `{0, 2}` which is not equal to `{2}`. Anyways, the reason it's returning more than the row you want is because `board==rows` still returns `False, True, False, False` at row 2, and so that `True` value is still included in the argument for `np.where()`. – alkasm Jun 30 '17 at 15:39

3 Answers3

1

You don't need loops for this at all. For finding the rows that are filled with something other than 0, use .all(axis=1). The axis argument tells which axis to look for matching values across:

>>> (board != 0).all(axis=1)
array([False, False, False, False, False, False, False, False, False,
    True, False], dtype=bool)

The booleans are True wherever there is a row filled with non-zero values, and False otherwise. If you take the outer product with a row array full of True values, you'll get True exactly in your matrix locations corresponding to the full row:

>>> np.outer((board!=0).all(axis=1),np.ones(board.shape[1], dtype=bool))
array([[False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [False, False, False, False],
       [ True,  True,  True,  True],
       [False, False, False, False]], dtype=bool)

Then you can get the indices of those True values with np.where():

>>> np.where(np.outer((board!=0).all(axis=1),np.ones(board.shape[1], dtype=bool)))
(array([9, 9, 9, 9]), array([0, 1, 2, 3]))

Note that np.where() returns np.int64 values. If you want np.int32 then just assign variables and convert them:

>>> yind, xind = np.where(np.outer((board!=0).all(axis=1),np.ones(board.shape[1], dtype=bool)))
>>> yind = np.int32(yind)
>>> xind = np.int32(xind)
>>> yind, xind
(array([9, 9, 9, 9], dtype=int32), array([0, 1, 2, 3], dtype=int32))

To instead put all of these indices as tuples, use zip(*) (see here for an explanation if you're not familiar with * unpacking):

>>> [(y,x) for y,x in zip(*np.where(np.outer((board!=0).all(1), np.ones(board.shape[1]))))]
[(9, 0), (9, 1), (9, 2), (9, 3)]

And again if you need np.int32 just specify that in the comprehension:

>>> [(y.astype(np.int32),x.astype(np.int32)) for y,x in zip(*np.where(np.outer((board == 2).all(1), np.ones(board.shape[1]))))]
[(9, 0), (9, 1), (9, 2), (9, 3)]
alkasm
  • 22,094
  • 5
  • 78
  • 94
  • Thanks to your answer, I was able to come up with this: `y, x = np.where(np.outer((board == 2).all(1), np.ones(board.shape[1]))) pending_rows_indices = [(y, x) for x, y in zip(x, y)] print(pending_rows_indices)` I have one more question, is there a way to write this with list comprehension? Using zip as well. – Cast Fellow Jun 30 '17 at 16:12
  • @CastFellow sure, use `zip(*np.where(...))`. E.g. `pending_row_indices = [(y,x) for y,x in zip(*np.where(np.outer((board == 2).all(1), np.ones(board.shape[1]))))]` gives you `[(9, 0), (9, 1), (9, 2), (9, 3)]`. I edited my post to include this at the end. – alkasm Jun 30 '17 at 16:41
0

If i understood well you are trying to find the row where your numpy array is completely filled ( no 0 values )

so i ask of you to consider this:

import numpy as np
board = np.array([[0, 0, 0, 0],
                  [0, 0, 0, 0],
                  [0, 2, 0, 0],
                  [1, 1, 1, 1],   # added this one just to generalize in 
                  [0, 0, 0, 0],   # case you have numbers != 2
                  [0, 0, 0, 0],
                  [0, 0, 0, 0],
                  [0, 0, 0, 0],
                  [0, 0, 0, 0],
                  [2, 2, 2, 2],
                  [0, 0, 0, 0]])
for i,rows in enumerate(board):
    if not 0 in set(rows): # changed this to work on all non zero numbers
        print(rows)
        if len(set(rows)) <= 1:
            print(i)

output:

[1 1 1 1] # first row filled
3         # its index as int ( if that's what you're looking for )
[2 2 2 2] # seconds row filled
9         # its index as int

all you needed is enumerate built-in function. Happy Coding

Rayhane Mama
  • 2,374
  • 11
  • 20
0

If I understood your problem correctly, you want to find the row index of a specific element in the array. So, you need the following print() statement instead of print(np.where(board == rows)).

print(np.where((board == rows).all(axis=1)))

It outputs:

(array([9], dtype=int64),)

To get the specific row number, you can do the following.

loc = np.where((board == rows).all(axis=1))
print(loc[0][0]) # prints 9

Complete program:

import numpy as np
board = np.array([[0, 0, 0, 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, 0, 0, 0],
                  [2, 2, 2, 2],
                  [0, 0, 0, 0]])
for rows in board:
    if set(rows) == {2}:
        print(rows)
        if len(set(rows)) <= 1:
            print(np.where((board == rows).all(axis=1)))
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161