Alby
Alby

Reputation: 27

C# - fair team allocation with ratings

I have a list of rankings for players in a sport and would like to assign them to teams so that the distribution of ratings is as fair as possible (i.e. eliminating teams with lots of high rated players and vice versa).

Currently I am doing this but it doesn't seem to give the optimal solution:

ratingList.Sort();
ratingList.Reverse();

var team1List = ratingList.Where((r, i) => i % 2 != 0).ToList();
var team2List = ratingList.Where((r, i) => i % 2 == 0).ToList();

Upvotes: 1

Views: 131

Answers (2)

mariovalens
mariovalens

Reputation: 365

For the optimal solution, the idea is to consider the ratingList twice side by side ascending vs descending and take the first half (the other one is just mirrored)

Ex:
0, 1, 2, 3, 4 | 5, 6, 7, 8, 9
9, 8, 7, 6, 5 | 4, 3, 2, 1, 0

and keep the first half

team1 team2 team1 team2 |
0,    1,    2,    3,    | 4 team1
9,    8,    7,    6,    | 5 team2

The evens go in team1 and the odds in team2. If we have an even number of pairs, the last pair will be redistributed between the two teams (also please note that this works only for ratingList >= 4 (it's up to you to handle for less). Also for even number of ratings I propose to exclude the middle rating and decide later what to do with it.

Considering all the above, the solution should look like this

ratingList.Sort();
var count = ratingList.Count();

// if even number of players, keep aside the one in the middle (as rating)
int? middle = null;
if (count % 2 != 0)
{
    middle = ratingList[count / 2];
    ratingList.RemoveAt(count / 2);
}

var ratingListDesc = ratingList.OrderByDescending(i => i).ToList();

var half = count / 2;
var take = half % 2 != 0 ? half - 1 : half;

var team1List = ratingList.Take(take).Where((r, i) => i % 2 == 0).ToList();
team1List.AddRange(ratingListDesc.Take(take).Where((r, i) => i % 2 == 0));

var team2List = ratingList.Take(take).Where((r, i) => i % 2 != 0).ToList();
team2List.AddRange(ratingListDesc.Take(take).Where((r, i) => i % 2 != 0));

// we just have to redistribute the remaining pair between each team
if (half % 2 != 0)
{
     team1List.Add(ratingList[half - 1]);
     team2List.Add(ratingListDesc[half - 1]);
}

if (middle.HasValue)
{
    // do something, or not ...
}

Upvotes: 0

mariovalens
mariovalens

Reputation: 365

After sorting them in descending order try this

var team1List = ratingList.Where((r, i) => i % 2 != 0).ToList();
var team2List = ratingList.Where((r, i) => i % 2 == 0).ToList();

Upvotes: 1

Related Questions