Give a element rank list of a list
Assuming your lists are positive integers as in OP, this should be quite fast, particularly if duplication is high. Fiddle with using Union
vs Sort@DeleteDuplicates
- each will have an advantage depending on data.
Normal[SparseArray[
With[{us = Sort@DeleteDuplicates@#}, us -> Range@Length@us]][[#]]]&@yourlist
For any kind of data, this s/b quick also:
Replace[#, PositionIndex[Sort@DeleteDuplicates@#][[All, 1]], 1] &@yourlist
or probably a bit quicker yet for general data:
Replace[#,
With[{s = Sort@DeleteDuplicates@#},
AssociationThread[s, Range@Length@s]], 1] &@yourlist
A possible approach:
position[list_List] := Module[{n = 1, f},
f[x_] := f[x] = n++;
f /@ Union[list];
f /@ list
];
Examples:
SeedRandom[417];
list1 = RandomChoice[Range[22, 28], 4];
position[list1]
(* {1, 3, 4, 2} *)
SeedRandom[416];
list2 = RandomChoice[Range[22, 28], 4];
position[list2]
(* {3, 1, 2, 1} *)
A few timings:
SeedRandom[416];
list3 = RandomChoice[Range[22, 28], 10^6];
position[list3]; // AbsoluteTiming
(* {0.672818, Null} *)
SeedRandom[417];
list4 = RandomChoice[Range[10^5], 10^5];
position[list4]; // AbsoluteTiming
(* {0.379642, Null} *)
A replacement-Rule
-based approach:
rankList[lst_List] := lst /. Dispatch[Thread[# -> Range@Length@#] &@ Union@lst]
It's a little bit of speed-up over Xavier's solution (position
):
SeedRandom[416];
list3 = RandomChoice[Range[22, 28], 10^6];
rankList[list3]; // AbsoluteTiming // First
position[list3]; // AbsoluteTiming // First
rankList[list3] === position[list3]
(* 0.287793 *)
(* 0.584785 *)
(* True *)
SeedRandom[417];
list4 = RandomChoice[Range[10^5], 10^5];
rankList[list4]; // AbsoluteTiming // First
position[list4]; // AbsoluteTiming // First
rankList[list4] === position[list4]
(* 0.108716 *)
(* 0.281810 *)
(* True *)
Note: Dispatch
is absolutely crucial here. Without it, the second example runs for a long time. Alternatively, use Association
s (suggested by Xavier in a comment), which serve the same purpose:
rankList1[lst_List] := lst /. (AssociationThread[# -> Range@Length@#] &@Union@lst)