Reputation: 27
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
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
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