Вы можете сделать это прямо в NumPy без каких-либо исключений, так как вы знаете размеры вашего массива. Индексы ближайших соседей x, y
задаются как
inds = np.array([[x, y]]) + np.array([[1, 0], [-1, 0], [0, 1], [0, -1]])
. Вы можете легко создать маску, которая указывает, какие индексы действительны:
valid = (inds[:, 0] >= 0) & (inds[:, 0] < arr.shape[0]) & \
(inds[:, 1] >= 0) & (inds[:, 1] < arr.shape[1])
Теперь извлеките значения, которые выwant:
inds = inds[valid, :]
vals = arr[inds[:, 0], inds[:, 1]]
Простейшим возвращаемым значением будет inds, vals
, но если вы настаиваете на сохранении своего исходного формата, вы можете преобразовать его в
[v, tuple(i) for v, i in zip(vals, inds)]
Addendum
Вы можете легко изменить это для работы с произвольными измерениями:
def neighbors(arr, *pos):
pos = np.array(pos).reshape(1, -1)
offset = np.zeros((2 * pos.size, pos.size), dtype=np.int)
offset[np.arange(0, offset.shape[0], 2), np.arange(offset.shape[1])] = 1
offset[np.arange(1, offset.shape[0], 2), np.arange(offset.shape[1])] = -1
inds = pos + offset
valid = np.all(inds >= 0, axis=1) & np.all(inds < arr.shape, axis=1)
inds = inds[valid, :]
vals = arr[tuple(inds.T)]
return vals, inds
Учитывая N размерного массива arr
и N элементов pos
, вы можете создать смещения с помощьюпросто устанавливая каждое измерение последовательно на 1
или -1
. Вычисление маски valid
значительно упрощается за счет широковещательной передачи inds
и arr.shape
, а также вызова np.all
по каждой строке размера N вместо того, чтобы делать это вручную для каждого измерения. Наконец, преобразование tuple(inds.T)
превращает inds
в фактический причудливый индекс, присваивая каждому столбцу отдельное измерение. Транспонирование необходимо, потому что массивы повторяются по строкам (dim 0).