Home > database >  Bingo in Numpy array
Bingo in Numpy array

Time:02-02

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:

  1. 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 matrix A.

  2. 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 matrix A.

  3. My code won't work if the matrix A contains duplicate elements.

Can anyone suggest a general and numpyic way to do this?

CodePudding user response:

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

CodePudding user response:

Here is a solution for the first two cases

def bingo(a, A):
    if len(a)==1:
        return a in A
    positions = np.argwhere(np.isin(A, a))
    not_reversed = A[positions[0,0],positions[0,1]] == a[0]
    return np.max(np.diff( positions.T )) * not_reversed 

However your use of max may not be foolproof. For example f = np.array([ 1, 2, 6 ]) will be considered as being in A. I'm starting to wonder if the simplest solutions wouldn't be to check for array length, and then check column by column, line by line and diagonal by diagonal...

  •  Tags:  
  • Related