Skip to content

Instantly share code, notes, and snippets.

@leemeichin
Created October 9, 2012 16:11
Show Gist options
  • Save leemeichin/3859792 to your computer and use it in GitHub Desktop.
Save leemeichin/3859792 to your computer and use it in GitHub Desktop.
Apply Standard Competition Rankings to your leaderboard

Standard Competition Rankings

This class makes it easier to generate a leaderboard that complies with the Standard Competition Ranking system. That is, it takes joint/tied positions into account, and adjusts the positions accordingly.

Take the following list of users and points for example:

User    | Points
1         35
2         35
3         50
4         10
5         35

You might be contented with a leaderboard like this:

User    | Points    | Position
3         50          1
2         35          2
1         35          3
5         35          4
4         10          5

Users 2, 1 and 5 all have the same points, so what makes user 2 come second, and user 5 come fourth? That can't be right!

What you really need is this:

User    | Points    | Position
3         50          1
2         35          2
1         35          2
5         35          2
4         10          5

Which you can do with the code in this gist!

ranking_data = {...} # hash representation of above user/points table

leaderboard = StandardCompetitionRankings.new(ranking_data, :rank_by => :points, :sort_direction => :desc)
better_leaderboard = leaderboard.calculate

If you don't want any sorting applied because you want to roll your own or whatever, set the :sort_direction parameter to nil or false.

After all that, it will append a field called position to your dataset, which contains your now standardised rankings, and return the whole thing. :)

class StandardCompetitionRankings
def initialize(data, options = {})
@data = data
@options = options.reverse_merge(:rank_by => :points, :sort_direction => :desc)
end
def sort_data!
return if @options[:sort_direction].nil? or @options[:sort_direction] == false
case @options[:sort_direction]
when :desc then @data.sort! {|a, b| b[@options[:rank_by]] <=> a[@options[:rank_by]] }
when :asc then @data.sort! {|a, b| a[@options[:rank_by]] <=> b[@options[:rank_by]] }
else raise ArgumentError, "Sort direction can only be :asc or :desc"
end
end
def calculate
return @rankings if @rankings.present?
@rankings = []
sort_data!
@data.each_with_index do |data, i|
if i == 0
data[:position] = 1
elsif data[@options[:rank_by]] == @data[i-1][@options[:rank_by]]
data[:position] = @rankings[i-1][:position]
else
data[:position] = i + 1
end
@rankings[i] = data
end
@rankings
end
end
require 'spec_helper'
describe StandardCompetitionRankings do
let!(:sample_data) do
%w(1000 2000 3000 3000 4000 5000 6000 7000 7000 9000).map {|points| {:points => points} }
end
describe '#calculate' do
it "should produce rankings with correctly calculated tied positions, sorted ascending" do
scr = Pokerfed::StandardCompetitionRankings.new(sample_data, :rank_by => :points, :sort_direction => :asc)
rankings = scr.calculate.map {|r| r[:position] }
rankings.should == [1, 2, 3, 3, 5, 6, 7, 8, 8, 10]
end
it "should produce rankings with correctly calculated tied positions, sorted descending" do
scr = Pokerfed::StandardCompetitionRankings.new(sample_data, :rank_by => :points, :sort_direction => :desc)
rankings = scr.calculate.map {|r| r[:position] }
rankings.should == [1, 2, 2, 4, 5, 6, 7, 7, 9, 10]
end
end
end
@dopa
Copy link

dopa commented Aug 28, 2013

THANK BOTH OF YOU!!! This really helped me with a project I'm working on!!!

@FlopTheNuts
Copy link

I'm trying to figure out the best way to extend this class a little to assign appropriate "points" based on standings.

For example, let's say I'm ranking 5 things and the positions come out as 1, 1, 3, 3, and 5. And points are assigned by position as 10, 8, 6, 4, 2.

When there's a tie for 1st, the points for 1st and 2nd should be summed and distributed among the ties. In this case, the resulting points would be:

9, 9, 5, 5, 2.

Any thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment