0

I have a 2d array of coordinates and I want to find the index of the entry that matches a given coordinate.

For example, my array could be A:

A = [[[1.5, 2.0], [1.0, 2.3], [5.4, 2.3]],
     [[3.2, 4.4], [2.0, 3.1], [0.0, 2.3]],
     [[1.0, 2.0], [2.3, 3.4], [4.0, 1.1]]]

and the coordinate I want to match is x = [1.0, 2.0]. I want to get the index of the coordinate [1.0, 2.0], which would be (2, 0).

Currently I am doing it as follows:

matching_inds = [(i, j) for i in xrange(len(A)) for j in xrange(len(A[0])) if A[i,j][0] == x[0] and A[i,j][1] == x[1]]

This works, but I feel like there should be something more efficient (the arrays I'm working with are much larger).

I tried np.where() but that doesn't seem to work too well with higher dimensions. It would return indices for all coordinates where the x-coordinate matched, not the x- and y-coordinates.

Any tips would be appreciated.

4
  • 1
    You have a 3D array though... Your list of lists holds more lists. Commented Jul 19, 2016 at 21:33
  • I guess you're right, strictly speaking. I view the innermost list as a tuple, though I know Python sees it as a list in its current form. Commented Jul 19, 2016 at 22:17
  • Can a point appear more than once in the array? And if so, what answer do you want if your search matches at more than one place? Commented Jul 20, 2016 at 20:26
  • Fortunately, the coordinates are unique, so I don't need to worry about multiple matches. Commented Jul 21, 2016 at 21:20

3 Answers 3

2

You could use a slightly simpler version of your code:

In [115]: A = [[[1.5, 2.0], [1.0, 2.3], [5.4, 2.3]],
     ...:      [[3.2, 4.4], [2.0, 3.1], [0.0, 2.3]],
     ...:      [[1.0, 2.0], [2.3, 3.4], [4.0, 1.1]]]

In [116]: x = [1., 2.]

In [117]: [(i, j) for i, row in enumerate(A) for j, coor in enumerate(row) if coor == x]
Out[117]: [(2, 0)]

But if the arrays are large, you'd better use a vectorized approach:

In [118]: import numpy as np

In [119]: arr = np.array(A)

In [120]: np.argwhere(np.logical_and(arr[:,:,0] == x[0], arr[:,:,1] == x[1]))
Out[120]: array([[2, 0]], dtype=int64)

Edit: An efficient and elegant way of getting the job done would be:

In [158]: np.argwhere(np.all(arr == x, axis=2))
Out[158]: array([[2, 0]], dtype=int64)
Sign up to request clarification or add additional context in comments.

2 Comments

I timed the edited version (np.all()) against the original (np.logical_and()) and found that the np.logical_and() is about 4 times quicker than np.all().
Interesting... Thank you for your feedback! Anyway, if you were to match three-dimensional rather than two-dimensional coordinates, the method that relies in np.all() would work perfectly fine, whereas you should tweak the the np.logical_and()-based code to get it to work.
1

You can possibly try this:

import numpy as np
arrA = np.array(A)
x = [1.0, 2.0]

np.where((arrA == x).sum(axis = 2) == 2)
# (array([2]), array([0]))

Comments

1

If you'll be doing a lot of lookups, you can build an index mapping the coordinates to positions in your matrix. E.g., (1.5, 2.0) maps to (0,0), (1.0, 2.3) maps to (0, 1), etc. Here's how to build an index of your array:

>>> A = [[[1.5,  2.0],[1.0,  2.3],[5.4,  2.3]],
...     [[3.2,  4.4],[2.0,  3.1],[0.0,  2.3]],
...     [[1.0,  2.0],[2.3,  3.4],[4.0,  1.1]]]
>>> revind = dict()
>>> for r, row in enumerate(A):
...     for c, pt in enumerate(row):
...         revind[tuple(pt)] = (r, c)
... 
>>> revind[(1.0, 2.0)]
(2,0)

Or as a (less readable) comprehension:

>>> revind = dict((tuple(pt), (r,c)) for r,row in enumerate(A) for c,pt in enumerate(row))

Note that you have to use tuples, since lists are "mutable" and cannot be used as dictionary keys. Doing it this way ensures that each lookup takes place in O(1) time, which is dramatically faster than searching a long list (as in your question and in the accepted answer).

1 Comment

Thanks for the suggestion. I only need to find one coordinate per large array, so a single search is more efficient for my purposes than creating a dictionary.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.