Reputation: 11
So basically I have to find the smallest number in a nested list as compared to the numbers around it. This would be called a 'sink' and the function returns True if it is a sink and False if it isn't. For example, if the nested list is
[[1, 2, 1],
[4, 6, 5],
[7, 8, 9]]
then the number at [0,2], (1), should be true as all the values adjacent to it are smaller than 1 but the number at [2, 0], (7), shouldn't be true as it is greater than some of the values around it.
I tried to use slicing to get the numbers beside it but I don't know how to slice it to get the number diagonal from the sink or above or below. This is some of the code that I tried to do:
for x in elevation_map:
for xs in x:
if elevation_map[cell[0]][cell[1]] < xs[cell[0]]:
return True
return False
Upvotes: 0
Views: 381
Reputation: 36249
If you consider a value a sink if it is the minimum of the surrounding 3x3 grid, i.e. you don't require that it is strictly smaller than any other value around it, then you can use numpy.lib.stride_tricks.as_strided
in order to create a window that checks the 3x3 neighbors. In order to work at the edges of the matrix, the original array can be padded with np.inf
(since min
is later used):
import numpy as np
matrix = np.array(
[[1, 2, 1],
[4, 6, 5],
[7, 8, 9]])
padded = np.pad(matrix.astype(float), 1, constant_values=np.inf)
window = np.lib.stride_tricks.as_strided(
padded,
padded.shape + (3, 3),
padded.strides * 2)[:-2, :-2]
result = matrix == window.min(axis=(-2, -1))
Which gives the following result:
[[ True False True]
[False False False]
[False False False]]
Upvotes: 0
Reputation: 23743
don't know how to slice it to get the number diagonal from the sink or above or below.
Your question shows an indexing scheme of [row,col]
.
Diagonals:
[row-1,col-1], [row-1,col+1], [row+1,col-1], [row+1,col+1]
left, right, up down:
[row,col-1],[row,col+1],[row-1,col],[row+1,col]
[row-1,col-1]
[row-1, col ]
[row-1,col+1]
[ row ,col-1]
[ row , col ]
[ row ,col+1]
[row+1,col-1]
[row+1, col ]
[row+1,col+1]
When calculating the indices you will need to include checks to see if you are at the edge of the 2-d structure. If you are at the left edge then col-1
will rap around to the last item in that row and if you are at the top edge then row-1
will rap around to the last item in that column. You also might want to check for the right and bottom edge - there won't be any cells at col+1
or row+1
.
Upvotes: 0
Reputation: 82889
You could convert your list of lists to a numpy
array, iterate the indices, and use two-dimensional slicing to get the sub-matrix and check whether the value at the current position is the minimal value.
>>> import numpy as np
>>> from itertools import product
>>> m = np.array([[1, 2, 1],
... [4, 6, 5],
... [7, 8, 9]])
...
>>> [(r, c, m[r,c]) for r,c in product(*map(range, m.shape))
... if m[r,c] == m[max(0,r-1):r+2,max(0,c-1):c+2].min()]
...
[(0, 0, 1), (0, 2, 1)]
(The max(0, ...)
is so that the lower bound 0-1
does not refer to the last element in the array; if the upper bound is higher then the size of the array, that's not a problem.)
Note: This will also identify a point as a "sink" if one of it's neighbors has the same value; not sure if this is a problem.
Upvotes: 1