pythonnumpycolorama

How to check if an element in an array is surrounded by another specific element


This problem was presented to me through an exam and the exercise was to create a randomly generated 10x10 array with 0s and 1s. Then you had to color them accordingly. If any 1s are surrounded on all sides by 0s then do not color them. I've gone half way through the exercise and can't seem to figure out a way to do the last task.

import numpy as np
from colorama import Fore
random_matrix = np.random.randint(0, 2,(10, 10))
print(random_matrix)
for row in random_matrix:
    for i in row:
        if i == 0:
            i = (Fore.RED + str(i))
        if i == 1:
            i = (Fore.BLUE + str(i))
        print(i, end=' ')
    print()

Solution

  • Since your explanation isn't precise enough I am not going to do exactly what you're asking for. E.g. what do you mean by surrounded and you're just saying what you do not want but do you want to color the rest? So instead I just show how one might do something similar.

    I take a random 10 by 10 array of zeros and ones and color anything that's surrounded by zeros. And by surrounded I mean all 4 sides zeros or 2/3 sides if it is a corner/border spot.

    My idea is that I shift the array in those 4 directions and combine the negative of the result with logical and. The problem is that if I take numpy's roll for that it considers things at a boundary to be neighboured by the boundary on the other site. So I must set those to zero.

    Here I generate the 10 by 10 array.

    import numpy as np
    import pandas as pd
    import itertools
    import functools
    
    np.random.seed(0)
    arr = np.random.randint(0,2,size=(10,10))
    

    I define the special roll as described above and combine it to get the surrounded spots.

    def my_roll(arr, shift=None, axis=None):
        arr = np.roll(arr, shift=shift, axis=axis)
        pos = 0 if shift > 0 else -1
        idx = tuple(Ellipsis if i != axis else pos for i in range(len(arr.shape)))
        arr[idx] = 0
        return arr
    
    surrounded = functools.reduce(np.logical_and, [np.roll(arr,shift=shift, axis=ax)==0 
                                                    for ax,shift in itertools.product((0,1),(-1,1))])
    

    Here I could call it done and you can stop reading but I will also include the code I used to plot the result.

    @np.vectorize
    def surrounded_styler(x):
        return 'color:red;' if x else None
    
    def style_negative(v, props=''):
        return props if v > 0 else None
    
    pd.DataFrame(arr).style.apply(lambda df:surrounded_styler(surrounded), axis=None)
    

    enter image description here