0

I am trying to compute a distance between an element and a starting point in an array.

Here is an array

enter image description here

assume the element (0,1) is a starting point which has the highest value currently.

a neighbors is an element around a specific point if they have one axis in common and different in another axis by 1 unit.

generally, a neighbor could be the top, bottom, left, right of a specific point, which is inside the array.

the task is to label every elements with a distance value indicate how far it is from the starting point (0,1).

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

dist = np.full_like(ds, -1)
p0 = np.where(ds == 2)
dist[p0] = 0
que = []
que.append(p0)
nghb_x = [0, 0, -1, 1]
nghb_y = [-1, 1, 0, 0]

while len(que):
    x, y = que.pop()
    d = dist[(x,y)]
    for idx0, idx1 in zip(nghb_x, nghb_y):
        tmp_x = x + idx0
        tmp_y = y + idx1
        if np.any(tmp_x >= 0) and np.any(tmp_x < ds.shape[0]) and np.any(tmp_y >= 0) and np.any(tmp_y < ds.shape[1]) and np.any(dist[(tmp_x,tmp_y)] == -1):
            dist[(tmp_x,tmp_y)] = d + 1 # distance = distance(x) + 1
            que.append((tmp_x, tmp_y))

print('dist:')
print(dist)

the output

dist:
[[1 0 1]
 [2 1 2]
 [3 2 3]]

is as expected though, I would like to know if is there a more efficient way to do this?

4
  • By more efficient do you mean faster, using less memory or with less lines of code? Commented Apr 30, 2019 at 22:52
  • You want the Manhattan distance. Commented Apr 30, 2019 at 22:54
  • Can also build a graph and use nx.shortest_path_length. Commented Apr 30, 2019 at 22:55
  • You can just iterate every point and calculate the distance as the sum of the difference between the x coords, and the difference between the y coords, of the point and the target. Commented Apr 30, 2019 at 22:55

1 Answer 1

4

You're calculating the Manhattan distance (the x-distance plus the y-distance) from a target point for each point.

You can use a numpy function to do it in one step, given the target coordinates and the shape of the array:

target = (0, 1)
np.fromfunction(lambda x,y: np.abs(target[0]-x) + np.abs(target[1]-y), ds.shape)    

Result:

[[1. 0. 1.]
 [2. 1. 2.]
 [3. 2. 3.]]

Demo: https://repl.it/repls/TrustyUnhappyFlashdrives

Sign up to request clarification or add additional context in comments.

2 Comments

There's little improvement to this answer, except perhaps to note that, depending on what you mean to use the resulting array for, you might be more efficient by just defining a function that gives you the distance for a pair of coordinates and only perform the computation for coordinates you actually use it for.
Or more directly: np.abs(target[0]-np.arange(3))[:,None] + np.abs(target[1]-np.arange(3)). fromfunction seems to confuse beginners, making them think it is doing something profound. stackoverflow.com/questions/55930785/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.