I've noticed that PositionIndex does not take a level spec like most related functions. So while it's very useful on 1D lists, I can't really use it to get a index of a matrix for example. Now I'm wondering what an efficient replacement is.
I'm aware of this post which contains two handwritten alternatives to PositionIndex that are faster in the 1D case.
However, since I know that the values in my matrix are small consecutive integers (in fact it's a label matrix obtained from MorphologicalComponents), I don't really need the result to be an association, and I've found a simple Array over Positions to be faster:
matrix = RandomInteger[{1, 10}, {1000, 1000}];
Array[Position[matrix, #] &, Max@matrix]; // AbsoluteTiming
GroupBy[Tuples[Range@Length@matrix, 2], matrix[[## & @@ #]] &]; // AbsoluteTiming
{0.910396, Null} {2.73593, Null}
The Array approach seems wasteful though because it needs to go over the matrix several times. Then again, I can speed this one up a bit more in my own case, because I don't care about the positions of the 0s in the label matrix.
Is there a better way to generalise the GroupBy approach to multiple dimensions? Or is there some third approach that would be a useful replacement for PositionIndex when I'm dealing with data that has more structure than a 1D list?
Merge[PositionIndex /@ matrix, Join]– Alexey Golyshev Mar 30 '17 at 16:40matrixand its transpose and then zip the two results together. I might try that, but I'm not sure it will be particularly efficient (although then I can swap in the faster replacement forPositionIndexagain). – Martin Ender Mar 30 '17 at 16:42Merge[Table[Thread[{i,#}]&/@PositionIndex[matrix[[i]]],{i,Length@matrix}],Join]– Alexey Golyshev Mar 30 '17 at 16:49Join@@#&, but that's already faster, thanks. – Martin Ender Mar 30 '17 at 16:52cleanPosIdxormyPosIdxfrom the other question is slower thanPositionIndexin this case. – Martin Ender Mar 30 '17 at 16:54