Prompted by some conversation in comments elswhere, my method.
Module[{o},
If[OrderedQ[#], Most@Accumulate@Prepend[Tally[#][[All, 2]], 1],
o = Ordering[#];
o[[Most@Prepend[Accumulate[Tally[#[[o]]][[All, 2]]] + 1, 1]]]]] &[targetListHere]
Can clobber GatherBy
method by over an order of magnitude (e.g. on RandomInteger[1*^6,1*^5]
my tests showed ~11X faster). On the same test size with a sorted list, this was around ~30X faster than GatherBy
. Much more frugal RAM use compared to GB also...
Of course, taking advantage of the structure of your data (non-negative integers of a fairly limited range) this and all the other posted methods can be clobbered performance-wise with
findFirstOccurPos[list_] :=
Module[{z = ConstantArray[0, Max[list] + 1]},
z[[Reverse@(list + 1)]] = Range@Length@list;
(Length@list + 1) - SparseArray[z]["NonzeroValues"]]
Taking further advantage of the structure and random distribution of your example, we can boost performance another 5-6X with selective list "snooping" that short-circuits the process:
findFirstOccurPosSC[list_] :=
Module[{lens = Ceiling[Length@list/{100, 50, 20, 10, 5, 1}],
z = ConstantArray[0, Max[list] + 1],
need = Length@DeleteDuplicates@list, result, l},
Catch[Do[l = list[[;; curlen]];
z[[Reverse@(l + 1)]] = Range@curlen;
result = (curlen + 1) - SparseArray[z]["NonzeroValues"];
If[Length@result == need, Throw[result]];
, {curlen, lens}]; result]]
This will be in general ~30X faster than using GatherBy
on large lists.