pythonlistgridviewnearest-neighbor

python find all neighbours of a given node in a list of lists


I am trying to find a way to find all neighbours of a given node in a list of lists. The array looks like this:

0,2,4,1,6,0,0
2,0,0,0,5,0,0
4,0,0,0,5,5,0
1,0,0,0,1,1,0
6,5,0,1,0,5,5
0,0,5,1,5,0,0
0,0,0,0,5,0,0

So far my code is:

#!/usr/bin/python

#holds all source nodes
source = []

#read in and store the matrix
def create_matrix(file):
    with open('network.txt') as f:
        Alist = []
        for line in f:
            part = []
            for x in line.split(','):
                part.append(int(x))
            Alist.append(part)
    return Alist

def check_neighbours(Alist):
    i = iter(Alist)
    item = i.next()
    source.append(item)
    print source

file = ("F:/media/KINGSTON/Networking/network.txt")
Alist = create_matrix(file)
check_neighbours(Alist)

Obviously this only outputs the first row of the matrix but I am wanting something a little different. For example, I would start at the node [0,0] which is 0 and then find both [0,1] and [1,0]. But I also need to look in a 3x3 radius if I am not on the edge of the matrix. I know how to find the next neighbour to the right of the current node but I am really not sure how to find anything next to the node which includes diagonal nodes as well.


Solution

  • You want a 8-neighbor algorithm, which is really just a selection of indices from a list of lists.

    # i and j are the indices for the node whose neighbors you want to find
    # dist is the finding distance around the node
    def find_neighbors(m, i, j, dist=1):
        return [row[max(0, j-dist):j+dist+1] for row in m[max(0, i-dist):i+dist+1]]
    

    Which can then be called by:

    m = create_matrix(file)
    i = some_y_location
    j = some_x_location
    neighbors = find_neighbors(m, i, j)
    

    The implementation without list compression:

    def find_neighbors(m, i, j, dist=1):
        neighbors = []
        i_min = max(0, i-dist)
        i_max = i+dist+1
        j_low = max(0, j-dist)
        j_max = j+dist+1
        for row in m[i_min:i_max]:
            neighbors.append(row[j_min:j_max])
        return neighbors
    

    You need the max call for the i/j_min to avoid negative indices, but the upper values being too large are handled by list slices automatically.

    If you want those row lists as a single element list you need to add:

    neighbors = [elem for nlist in neighbors for elem in nlist]
    

    This flattens the list of lists.

    If you want the indicies of neighbors instead (there are probably cleaner solutions):

    def find_neighbor_indices(m, i, j, dist=1):
        irange = range(max(0, i-dist), min(len(m), i+dist+1))
        if len(m) > 0:
            jrange = range(max(0, j-dist), min(len(m[0]), j+dist+1))
        else:
            jrange = []
        for icheck in irange:
            for jcheck in jrange:
                # Skip when i==icheck and j==jcheck
                if icheck != i or jcheck != j:
                    neighbors.append((icheck, jcheck))
        return neighbors