Search code examples
javascriptalgorithmember.jsranking

Ember ranking algorithm


I need to create a simple ranking algorithm in Ember. It needs to take an array of Ember models and produce an ordinal that in case of ties assigns the same rank and skips the tied ranks accordingly. The number of items in each array is small, so performance is not a critical consideration. I'd like to maintain Ember idioms where possible.

Example:

// models/competition.js
export default Model.extend({
    competitors: hasMany('competitor')
    ranks: computed.[ranking function here]
});

// models/competitor.js
export default Model.extend({
    name: attr('string'),
    score: attr('number'),
    competition: belongsTo('competition')
    rank: computed.[return rank here]
});

Then, given the following competitors, scores:

Alpha, 100
Beta, 90
BetaPrime, 90
BetaDoublePrime, 90
Gamma, 80

I'd like the rank computed property to return as follows:

Alpha, 1
Beta, 2
BetaPrime, 2
BetaDoublePrime, 2
Gamma, 5

I can do this in python but I'm new to Ember/Javascript and can't quite figure this out. I'm sure some combination of map/reduce is the key, but am otherwise clueless... Thanks.


Solution

  • If you want to compute the rankins in the competition model, I would do something like this:

    ranks: Ember.computed('competitors', function() {
        let lastScore = null;
        let lastRank = null;
        return this.get('competitors').sortBy('score').reverse().map((competitor, index) => {
           let score = competitor.get('score');
           let rank = score === lastScore ? lastRank : index+1;
           lastScore = score;
           lastRank = rank;
           return {
               competitor: competitor, 
               rank: rank
           };
        });
    })
    

    This will first sort the competitors by score (you can define multiple properties to sort on, for example to decide what to do when the score is equal) , reverse the result to get the highest score first and then return an object for each sorted competitor with the competitor itself and the rank.

    I think it's not a good idea to save this in the competitor model, a rank belongs to a competition (although in your situation a competitor seems to be part of only one competition). If you want to get the rank of a competitor, just look it up in the competition.