This issue has largely been mitigated in 10.0.1. New timings for the final test below are:
Needs["GeneralUtilities`"]
a = RandomInteger[9, 5*^5];
myPosIdx[a] // AccurateTiming
cleanPosIdx[a] // AccurateTiming (* see self-answer below *)
PositionIndex[a] // AccurateTiming
0.01493840.0149554
0.0545865
Still several times slower here than the readily available alternatives but no longer devastating.
Disconcertingly I have discovered that the new (v10) PositionIndex is horribly slow.
Using Szabolcs's clever GatherBy inversion we can implement our own function for comparison:
myPosIdx[x_] :=
<|Thread[x[[ #[[All, 1]] ]] -> #]|> & @ GatherBy[Range @ Length @ x, x[[#]] &]
Check that its output matches:
RandomChoice[{"a", "b", "c"}, 50];
myPosIdx[%] === PositionIndex[%]
True
Check performance in version 10.0.0 under Windows:
a = RandomInteger[99999, 5*^5];
myPosIdx[a] // Timing // First
PositionIndex[a] // Timing // First
0.1404010.920406
Not a good start for the System` function, is it? It gets worse:
a = RandomInteger[999, 5*^5];
myPosIdx[a] // Timing // First
PositionIndex[a] // Timing // First
0.0312002.230814
With fewer unique elements PositionIndex actually gets slower! Does the trend continue?
a = RandomInteger[99, 5*^5];
myPosIdx[a] // Timing // First
PositionIndex[a] // Timing // First
0.01560015.958902
Somewhere someone should be doing a face-palm right about now. Just how bad does it get?
a = RandomInteger[9, 5*^5];
myPosIdx[a] // Timing // First
PositionIndex[a] // Timing // First
0.015600157.295808
Ouch. This has to be a new record for poor computational complexity in a System function. :o



PositionIndexcomputes what is claimed. – Michael E2 Jul 15 '14 at 01:06SunPosition is horribly slowrant here and used Wolfram Community. :) – Sjoerd C. de Vries Jul 15 '14 at 05:51GroupBy, it is a bit slower than yours, but it is nice and succinct:posIdx[x_] := GroupBy[Range@Length@x, (x[[#]] &) -> Identity]. – rcollyer Jul 15 '14 at 12:56PositionIndexis performing poorly, but loses out when there are few collisions. That said, the grouping syntax is awesome, and once I get used to it, it will replace my use ofSelectEquivalentsas it does the fast majority of what I want to do. – rcollyer Jul 15 '14 at 13:09GroupBy[Range @ Length @ x, x[[#]] &]sufficient? – Mr.Wizard Jul 15 '14 at 13:10GroupBymethod as an answer? – Mr.Wizard Jul 15 '14 at 13:14PositionIndexdoes work correctly with held expressions, whereas this is a bit painful to implement usingGatherBy.a = 1; PositionIndex[Unevaluated[{a, b, c, d}]]– Jacob Akkerboom Jul 15 '14 at 14:51f[x_] := AssociationThread @@ {Hold[Unevaluated[x]][[1, {1}, #[[All, 1]]]], #} &@ GatherBy[Range@Length@x, Hold[x][[{1}, #]] &]-- what did you write? – Mr.Wizard Jul 15 '14 at 15:04AssociationThread. I thought I had it and it worked for my first example, but I will have to debug it. – Jacob Akkerboom Jul 15 '14 at 15:29PositionIndexso horribly slow?" – geordie Jul 27 '14 at 12:19myPosIdxis still slightly faster. – RunnyKine Sep 17 '14 at 08:35cleanPosIdxposted below? – Mr.Wizard Sep 17 '14 at 09:36myPosIdx, but with fewer repititions, it is slightly slower than bothmyPosIdxandPositionIndex. – RunnyKine Sep 17 '14 at 09:47