Ranking a vector containing ties
list = {1, 2, 2, 3};
(Ordering@Ordering@# + Reverse@Ordering@Ordering@Reverse@#)/2 &@list
{1, 5/2, 5/2, 4}
As requested, here as a function:
rank[list_] := (Ordering@Ordering@list + Reverse@Ordering@Ordering@Reverse@list)/2
Both methods assume continuous sublists of identical elements, i.e., an already sorted vector. Gather
is ~10x faster than Union
for larger lists.
x = {1, 2, 2, 3};
f1[x_] := x /. (# -> Mean @ Flatten@Position[x, #] & /@ Union@x);
f2[x_] :=
Module[{i = 1}, x /. ((First @ # -> (i + (i = i + Length @ #) - 1)/2) & /@ Gather@x)];
{f1@x, f2@x}
{{1, 5/2, 5/2, 4}, {1, 5/2, 5/2, 4}}
y = Sort@RandomInteger[{0, 100}, {100000}];
AbsoluteTiming[r1 = f1@y;]
AbsoluteTiming[r2 = f2@y;]
r1 === r2
{2.090404, Null} {0.327601, Null} True