I don't know about the "elegant", but here's a short, easy to read, super-direct solution:
# assume a pre-sorted non-sparse array arr = [89, 52, 52, 36, 18, 18, 18, 18, 7] run = rank = 0 last_n = nil ranked = arr.map do |n| run += 1 next rank if n == last_n last_n = n rank += run run = 0 rank end p ranked
tested
I think we do it ...
Edit: This post has too much time, so I moved the test code to Gist: https://gist.github.com/jrunning/8549666d32a6bfa88e41
Here are the results:
falsetru 730.9 (±2.1%) i/s - 3672 in 5.025755s falsetru (2) 1289.9 (±2.7%) i/s - 6500 in 5.042749s sawa 986.9 (±2.1%) i/s - 5000 in 5.068450s Jordan 1644.9 (±1.9%) i/s - 8250 in 5.017334s Iceman 6.4 (±0.0%) i/s - 32 in 5.035015s simongarnier 1053.9 (±1.9%) i/s - 5304 in 5.034452s Cary Swoveland 511.4 (±3.5%) i/s - 2600 in 5.090605s
Edit: I had something here about Enumerator :: Lazy , but it turned out that I used it incorrectly. In any case, this did not improve performance.
Jordan running
source share