My starting point for this exercise was to apply a simple racing-rank to a list of integer values.

Here’s my list… 8, 4, 5, 6, 6, 3, 5, 9, 10, 1, 0, 6.

And this is my expectation…

0 = 1st
1 = 2nd
3 = 3rd
4 = 4th
5 = 5th (there are two items in 5th place)
6 = 7th (there are three items in 7th place)
8 = 10th
9 = 11th
10 = 12th

Here’s my first go…

IEnumerable<int> data = new[] { 8, 4, 5, 6, 6, 3, 5, 9, 10, 1, 0, 6 };

int rank = 0;
int next = 1;

Func<IGrouping<int, int>, int> getRank = (grouping) =>
{
    var answer = rank += next;
    next = grouping.Count();
    return answer;
};

var ranked = data
    .GroupBy(v => v)
    .OrderBy(v => v.Key)
    .Select(v => new
    {
        Group = v.Key,
        Rank = getRank(v)
    });

var result = ranked.ToList();

In my second scenario I imagined that my initial list of numbers were scores associated with players in a game. I want to calculate the rank for each player.

IEnumerable<Tuple<string,int>> data = new[] 
{ 
    new Tuple<string, int>("Andy", 8),
    new Tuple<string, int>("Belinda", 4),
    new Tuple<string, int>("Charles", 5),
    new Tuple<string, int>("David", 6),
    new Tuple<string, int>("Emma", 6),
    new Tuple<string, int>("Florence", 3),
    new Tuple<string, int>("George", 5),
    new Tuple<string, int>("Holly", 9),
    new Tuple<string, int>("Ira", 10),
    new Tuple<string, int>("Janice", 1),
    new Tuple<string, int>("Kelly", 0),
    new Tuple<string, int>("Laurence", 6),
};

int rank = 0;
int next = 1;

Func<IGrouping<int, Tuple<string, int>>, int> getRank = (grouping) =>
{
    var answer = rank += next;
    next = grouping.Count();
    return answer;
};

var ranked = data
    .GroupBy(v => v.Item2)
    .OrderBy(v => v.First().Item2)
    .Select(v => new
    {
        Items = v,
        Rank = getRank(v)
    })
    .SelectMany(v => v.Items, (s, i) => new
    {
        Item = i,
        Rank = s.Rank
    });

var result = ranked.ToList();

Next, I’m going to try and generalize this approach.