简体   繁体   中英

Sum of 8 neighbors in 2d array

I need to find the sum of all the neighboring elements of a cell, say getsumofneighbors(matrix, i, j) :

'M*N matrix'
[[0 1 0]
 [2 0 1]
 [0 4 0]
 [0 0 0]]

sum of nearest elements of cell [0][0] is 3

at [1][0] is 5

and at [1][1] is 8

Is there a python lib to find the sum of all the elements next to the given cell?

If you don't mind the dependency on scipy, you can use scipy.ndimage.convolve , as follows:

In [475]: a
Out[475]: 
array([[0, 1, 0],
       [2, 0, 1],
       [0, 4, 0],
       [0, 0, 0]])

In [476]: kernel
Out[476]: 
array([[1, 1, 1],
       [1, 0, 1],
       [1, 1, 1]])

In [477]: from scipy.ndimage import convolve

In [478]: c = convolve(a, kernel, mode='constant')

In [479]: c
Out[479]: 
array([[3, 3, 2],
       [5, 8, 5],
       [6, 3, 5],
       [4, 4, 4]])

You can use slicing and np.sum to calculate the sum of a particular region:

def getsumofneighbors(matrix, i, j):
    region = matrix[max(0, i-1) : i+2,
                    max(0, j-1) : j+2]
    return np.sum(region) - matrix[i, j] # Sum the region and subtract center

Notice that the max is there because negative starting indexes trigger different slicing.

Solution

def sum_neighbors(A, i, j):
    rows, columns = A.shape
    r0, r1 = max(0, i-1), min(rows-1, i+1)
    c0, c1 = max(0, j-1), min(columns-1, j+1)
    rs = list({r0, i, r1})
    cs = [[c] for c in list({c0, j, c1})]

    return A[rs, cs].sum() - A[i, j]

Explanation

Slice A by row before and after i with column before and after j . Take the sum and subtract cell at i , j . All other code is to handle the edges.

Demonstration

import numpy as np

mxn = np.array([[0, 1, 0],
                [2, 0, 1],
                [0, 4, 0],
                [0, 0, 0]])

for i, j in [(0, 0), (1, 0), (1, 1)]:
    s = "sum of neigbors for i={} and j={} is {}"
    print s.format(i, j, sum_neighbors(mxn, i, j))

sum of neigbors for i=0 and j=0 is 3
sum of neigbors for i=1 and j=0 is 5
sum of neigbors for i=1 and j=1 is 8

Following function should accomplish the task of finding the sum of all the neighboring elements of a cell:

def sum_around(matrix, r, c):
    total = 0
    offset = (0, 1, -1)
    indices = ((i, j) for i in offset for j in offset)

    next(indices, None)

    for rec in indices:
        try:
            row = r - 1 + rec[0]
            col = c - 1 + rec[1]
            total += matrix[row][col] if 0 <= row and 0 <= col else 0
        except IndexError:
            continue
    return total

Key points:

  • offsets defines relative changes needed for given indice to get surrounding elements (incl position of given indice himself because relative change [0][0] results in no change in indice)

  • due to order of elements in offset, indices generator object created in such way that first item is (0, 0). First item is consumed by next()

  • looping through generator object remaining elements, calculating and assigning values to matrix indices and adding values to total if indices are not negative (for obvious reasons) and continuing when indices are out of range (IndexError)

  • function expects that user will enter cell location in finger-based index and deduction -1 is needed for converting values to 0-based index

Just created this function which will do the job

def sumofnieghbors(MatrixObj, indexR, indexC):
    upperleft = 0
    if not (indexR < 1) or (indexC < 1):
        upperleft = MatrixObj[indexR - 1][indexC - 1]
    upper = 0
    if not (indexR < 1):
        upper = MatrixObj[indexR - 1][indexC]
    upperright = 0
    if not ((indexR < 1) or (indexC >= NbofCol)):
        upperright = MatrixObj[indexR - 1][indexC + 1]
    right = 0
    if not (indexC >= NbofCol):
        right = MatrixObj[indexR][indexC + 1]
    rightdown = 0
    if not ((indexR >= NbofRow) or (indexC >= NbofCol)):
        rightdown = MatrixObj[indexR + 1][indexC + 1]
    down = 0
    if not (indexR >= NbofRow):
        down = MatrixObj[indexR + 1][indexC]
    leftdown = 0
    if not ((indexR >= NbofRow) or (indexC < 1)):
        leftdown = MatrixObj[indexR + 1][indexC - 1]
    left = 0
    if not (indexC < 1):
        left = MatrixObj[indexR][indexC - 1]
    return (upperleft + upper + upperright + right + rightdown + down + leftdown + left)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM