2

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

Community
  • 1
  • 1
EasilyBaffled
  • 3,822
  • 10
  • 50
  • 87

1 Answers1

8

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]
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • Thanks, now here's one more if you'd like to answer, is there another data structure, like numpy or blist that would work better. I don't really know these two I just know they exist – EasilyBaffled Apr 26 '13 at 22:08
  • @EasilyBaffled: You may want to create a separate question for that. But you'll have to define what you mean by "work better" before anyone can answer. This is correct, very easy to understand, and almost certainly more than fast enough given your tiny data sizes. So, how could something be better than that? – abarnert Apr 26 '13 at 22:53
  • I hate to have to return after marking the answer, but the starmap((lambda a, b: grid[x + a][y + b]), can suffer from an index out of range error, anyone know how to adjust that? – EasilyBaffled May 01 '13 at 15:59
  • 1
    @EasilyBaffled See my edit, it should work on the edges of the grid now as well. – Andrew Clark May 01 '13 at 16:15
  • Great thanks, I was tempted to write my own fix, but I'm still trying to gain a good understanding of what's going on – EasilyBaffled May 01 '13 at 16:16
  • Sorry to ask you to do all this extra work, but I am stil trying to get a good understanding of what's going on here. Your fix is good unfortunately it was for the wrong part, it's the first part with lambda a, b: grid[x + a][y + b] that is going out of bounds. – EasilyBaffled May 01 '13 at 16:23
  • Can you edit your question or ask a new question with the data being used to cause the IndexError? My change should prevent the out of bounds error by limiting what `a` and `b` can be, is it possible that some rows in your grid have different lengths? – Andrew Clark May 01 '13 at 16:31
  • Also, you can still get index errors if you use `-1` for `x` or `y` in the function call, or use a value where `x >= len(grid)` or `y >= len(grid[0])`. These should be considered invalid calls because you would be asking for neighbors of a non-existent location, so raising an IndexError is appropriate behavior. – Andrew Clark May 01 '13 at 16:40