Reputation: 2125
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.
Upvotes: 0
Views: 3480
Reputation: 13743
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)
Upvotes: 2
Reputation: 50220
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).
Upvotes: 1
Reputation: 215117
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]))
Upvotes: 1