EasilyBaffled
EasilyBaffled

Reputation: 3882

Python, finding neighbors in a 2-d list

So here's the issue, I have a 2-d list of characters 'T' and 'F', and given coordinates I need to get all of its neighbors. I have this:

from itertools import product, starmap
x, y = (5, 5)
cells = starmap(lambda a, b: (x + a, y + b), product((0, -1, +1), (0, -1, +1))) 

from determining neighbors of cell two dimensional list But it will only give me a list of coordinantes, so i still fetch the values afterwords. I'd like the search and retrieval done in one step, so findNeighbors(5,5) would return F,T,F,F,... instead of (5, 4), (5, 6), (4, 5), (4, 4)... Is there a fast way of doing this? The solutin can include a structure other than a list to hold the initial information

Upvotes: 2

Views: 3885

Answers (1)

Andrew Clark
Andrew Clark

Reputation: 208425

The following should work, with just a minor adaptation to the current code:

from itertools import product, starmap, islice

def findNeighbors(grid, x, y):
    xi = (0, -1, 1) if 0 < x < len(grid) - 1 else ((0, -1) if x > 0 else (0, 1))
    yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
    return islice(starmap((lambda a, b: grid[x + a][y + b]), product(xi, yi)), 1, None)

For example:

>>> grid = [[ 0,  1,  2,  3],
...         [ 4,  5,  6,  7],
...         [ 8,  9, 10, 11],
...         [12, 13, 14, 15]]
>>> list(findNeighbors(grid, 2, 1))   # find neighbors of 9
[8, 10, 5, 4, 6, 13, 12, 14]
>>> list(findNeighbors(grid, 3, 3))   # find neighbors of 15
[14, 11, 10]

For the sake of clarity, here is some equivalent code without all of the itertools magic:

def findNeighbors(grid, x, y):
    if 0 < x < len(grid) - 1:
        xi = (0, -1, 1)   # this isn't first or last row, so we can look above and below
    elif x > 0:
        xi = (0, -1)      # this is the last row, so we can only look above
    else:
        xi = (0, 1)       # this is the first row, so we can only look below
    # the following line accomplishes the same thing as the above code but for columns
    yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
    for a in xi:
        for b in yi:
            if a == b == 0:  # this value is skipped using islice in the original code
                continue
            yield grid[x + a][y + b]

Upvotes: 8

Related Questions