Say I have a matrix
import numpy as np
A = np.array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
I want to check if an 1D array is included in this matrix horizontally, vertically or diagonally. Below is the code that I came up with
def bingo(a, A):
return np.max(np.diff(np.argwhere(np.isin(A, a)).T))
a1 = np.array([3, 4])
a2 = np.array([1, 5, 9])
a3 = np.array([5, 10, 15])
a4 = np.array([13, 10, 7, 4])
assert bingo(a1, A) == bingo(a2, A) == bingo(a3, A) == bingo(a4, A) == True
However, there are 3 major issues with my code:
-
I don’t want to consider the reverse case, which my code does. For example,
np.array([4, 3, 2, 1])should not be considered as being included in the matrixA. -
My code won’t work if the array only contains 1 element. For example,
np.array([1])should be considered as being included in the matrixA. -
My code won’t work if the matrix
Acontains duplicate elements.
Can anyone suggest a general and numpyic way to do this?
>Solution :
You need to test the rows, the columns and the two diagonals.
All individual cases are easy to perform, you can then combine them with or to have lazy evaluation (i.e., evaluation stops as soon as one match is found):
import numpy as np
A = np.array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
def bingo(A, test):
return (# rows
(A == test).all(1).any()
# cols
or (A.T == test).all(1).any()
# first diagonal
or (test == A.diagonal()).all()
# second diagonal
or (test == np.fliplr(A.T).diagonal()).all()
)
bingo(A, [1,2,3,4]) # True
bingo(A, [1,2,4,3]) # False
bingo(A, [2,6,10,14]) # True
bingo(A, [4,3,2,1]) # False
bingo(A, [1,6,11,16]) # True
bingo(A, [13,10,7,4]) # True