agoragames / leaderboard

Leaderboards backed by Redis in Ruby
https://rubygems.org/gems/leaderboard
MIT License
480 stars 65 forks source link

Handling ties #25

Closed stephenmckinney closed 12 years ago

stephenmckinney commented 12 years ago

This could be more of a question then a bug, but with the below members, why wouldn't the ranking be: 1, 2, 2, 4 due to a tie?

>> lb = Leaderboard.new 'best_of'
>> lb.rank_member 1234, 100
>> lb.rank_member 1235, 100
>> lb.rank_member 1236, 101
>> lb.rank_member 1237, 99
>> lb.leaders(1)
[
  [0] {
    :member => "1236",
      :rank => 1,
     :score => 101.0
  },
  [1] {
    :member => "1235",
      :rank => 2,
     :score => 100.0
  },
  [2] {
    :member => "1234",
      :rank => 3,
     :score => 100.0
  },
  [3] {
    :member => "1237",
      :rank => 4,
     :score => 99.0
  }
]
czarneckid commented 12 years ago

Redis doesn't understand the notion of a "tie". From the documentation on ZREVRANGE, "Descending lexicographical order is used for elements with equal score." or ZRANGE, "Lexicographical order is used for elements with equal score."

stephenmckinney commented 12 years ago

Thanks for the quick reply and great gem.

czarneckid commented 12 years ago

If your values are going to be solely integers, it's possible you could use something along the lines of score.timestamp as proposed in this thread.

stephenmckinney commented 12 years ago

Thanks, but in this case the scores are floats. This tie situation mattered most for us when we needed to decide the winners of a leaderboard. So we decided on this:

def winners(options = {})
  leaders = leaders(1, options)
  leaders.take_while { |x| x[:score] == leaders.first[:score] }
end