Search code examples
javascriptranking

Circular Ranking implementation in Javascript


Is there a way in javascript to establish a non-linear ranking hierarchy, something like a>b>c>a?

where something like:

> a>b
true
> b>c
true
> c>a
true

can always be consistent?


Solution

  • What you're referring to is a cyclic order. For example, consider the months of a year:

                           +----> March -----+
                           |                 |
                           |                 v
                 +----> February           April -----+
                 |                                    |
                 |                                    v
       +----> January                                May -----+
       |                                                      |
       |                                                      v
    December                                                 June
       ^                                                      |
       |                                                      |
       +----- November                              July <----+
                 ^                                    |
                 |                                    |
                 +----- October           August <----+
                           ^                 |
                           |                 |
                           +--- September <--+
    

    In a cyclic order it doesn't make sense to say things like “January comes before March” because it doesn't always come before March. However, it does make sense to say things like “after August, January comes before March” and “after February, March comes before January”.

    To put it in programming terms:

    after(August, January, March);   // true
    after(February, March, January); // true
    

    There's also a little hack which'll allow you to write code like this:

    after(August),   January < March; // true
    after(February), January > March; // true
    

    Here's how to make it work:

    const [ March
          , April
          , May
          , June
          , July
          , August
          , September
          , October
          , November
          , December
          , January
          , February ] = cycle();
    
    console.log((after(August),   January < March)); // true
    console.log((after(February), January > March)); // true
    
    function* cycle(n = 1, j = 0) {
        for (let i = 0; true; i++, n++) {
            yield {
                valueOf: () => (i + j) % n,
                get after() { j = n - i; }
            };
        }
    }
    
    function after(x) {
        return x.after;
    }

    On an interesting side note, did you know that March was the first month of the Roman calendar? Think about it:

    1. March marks the beginning of Spring, the season of new life. Hence, the beginning of the year coincides with the beginning of new life.
    2. If March is the first month then September, October, November and December are the 7th, 8th, 9th and 10th month respectively. Hence, they are called September (septa for 7), October (octa for 8), November (nona for 9) and December (deca for 10).

    Anyway, hope that helped.