Lets say we have a rank 2 array a with n entries that contain integer values in {0,1,2,...,m}. Now for each of those integers I want to find the indices of the entries of a with this value (called index_i, index_j in the following examples). (So what I'm looking for is like np.unique(...,return_index=True) but for 2d arrays and with the possibility to return all indices of each unique value.)
A naive approach would involve using boolean indexing which would result in O(m*n) operations (see below), but I'd like to only have O(n) operations. While I found a solution to do that, I feel like there should be a built in method or at least something that simplifies this - or that would at least remove these ugly loops:
import numpy as np
a = np.array([[0,0,1],[0,2,1],[2,2,1]])
m = a.max()
#"naive" in O(n*m)
i,j = np.mgrid[range(a.shape[0]), range(a.shape[1])]
index_i = [[] for _ in range(m+1)]
index_j = [[] for _ in range(m+1)]
for k in range(m+1):
index_i[k] = i[a==k]
index_j[k] = j[a==k]
#all the zeros:
print(a[index_i[0], index_j[0]])
#all the ones:
print(a[index_i[1], index_j[1]])
#all the twos:
print(a[index_i[2], index_j[2]])
#"sophisticated" in O(n)
index_i = [[] for _ in range(m+1)]
index_j = [[] for _ in range(m+1)]
for i in range(a.shape[0]):
for j in range(a.shape[1]):
index_i[a[i,j]].append(i)
index_j[a[i,j]].append(j)
#all the zeros:
print(a[index_i[0], index_j[0]])
#all the ones:
print(a[index_i[1], index_j[1]])
#all the twos:
print(a[index_i[2], index_j[2]])
(Note that I will need these indices for write access later, that is, for replacing the values stored in the array. But between these operations I do need to the 2d structure.)