Fairly rank values

Jelly, 10 8 bytes


Saved 2 bytes by using the cmp trick from @xnor's answer.

Try it online! or verify all test cases.

How it works

ð_'Ṡ‘S‘H  Main link. Left argument: A (list of values)

ð         Make the chain dyadic, setting the right argument to A.
 _'       Spawned subtraction; compute the matrix of differences.
   Ṡ      Apply the sign function to each difference.
    ‘     Increment.
     S    Sum across columns.
      ‘   Increment.
       H  Halve.

Pyth, 12


Test Suite

For each value this computes the arithmetic mean of [1..frequency] and adds the count of values less than the current one.

This works because for each value we would compute:

(1 / frequency) * sum (i = 1..frequency) i + count_less

which we can simplify to:

(1 / frequency) * [ frequency * (frequency + 1) / 2 + count_less * frequency ]

and again to:

(frequency + 1) / 2 + count_less

However, in Pyth it was golfier to compute the first summand by using the mean builtin, rather than this other formula.

Python 2, 51 bytes

lambda l:[-~sum(1+cmp(y,x)for x in l)/2.for y in l]

For each element y, the cmp expression gives 2 points for each smaller x and 1 point for each equal x. This sum is rescaled into the right range by adding 1 and halving. The 2. is needed to avoid integer division.

Python 3, 52 bytes

Python 3 lacks cmp, requiring a Boolean expression (+2 bytes), but it has float division (-1 byte).

lambda l:[-~sum((y>x)+(y>=x)for x in l)/2for y in l]