score:1
I don't know the rules of how teams are picked, but presumably exactly one player has to fill each of the six roles?
A brute force approach could work, if you don't have too many players (e.g. on the above table it might well work.)
Then, if you have n
players, there are n
choices for the first, n-1
for the second (because you can't have the same player in two different positions), etc. This gives a total of nP6
(falling factorial) possibilities. This is pretty large, of the order of n⁶
.
If you wanted to implement this, you could, to be quick and dirty, implement a six-deep loop (making sure to exclude players already chosen), check the score, and keep track of the highest one(s).
One way of cutting down the number of possibilities to check, which I think is sound, is this: choose your player in position X from only the top 6 scorers in that position. The intuition is this: if I've chosen (optimally or not) 5 players for my other positions, I can't have chosen all six of the best scorers for position X! So at least one of them is still available. Then I can't do better than choosing the best of them that's still left. So I can certainly exclude anyone from that position, who didn't score top 6. Issues may come in when there are ties, in which case, for safety, keep anyone who ties for any of the top 6 positions.
This way (assuming no ties), you only ever have to search through 6⁶
possibilities, at most (fewer if the same players are getting top 6 in different categories). And the initial search for top 6 will be tractable even for a large list.
Any or all of this could be done with LINQ, but it needn't be necessary.
score:0
So here's where it ended up.. Might help anyone battling with the logic of picking the highest possible total across a set of numbers. So far so good, I've not seen an instance where it doesn't return the correct result.. Feel free to suggest code clean-ups / optimizations.
private static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
{
return length == 1 ? list.Select(t => new[] {t}) : GetPermutations(list, length - 1).SelectMany(t => list.Where(o => !t.Contains(o)), (t1, t2) => t1.Concat(new[] {t2}));
}
public static List<PlayerScore> TeamOfTheWeek(List<PlayerScore> playerList)
{
// Remove the players who scored 0 accross the board.
playerList.RemoveAll(player => player.Forward + player.TallForward + player.Offensive + player.Defensive + player.OnBaller + player.Ruck == 0);
// Rank each player score within a position.
var forwardRank = playerList.RankByDescending(p => p.Forward, (p, r) => new {Rank = r, Player = p});
var tallForwardRank = playerList.RankByDescending(p => p.TallForward, (p, r) => new {Rank = r, Player = p});
var offensiveRank = playerList.RankByDescending(p => p.Offensive, (p, r) => new { Rank = r, Player = p });
var defensiveRank = playerList.RankByDescending(p => p.Defensive, (p, r) => new { Rank = r, Player = p });
var onBallerRank = playerList.RankByDescending(p => p.Defensive, (p, r) => new { Rank = r, Player = p });
var ruckRank = playerList.RankByDescending(p => p.Ruck, (p, r) => new { Rank = r, Player = p });
for (int i = playerList.Count - 1; i >= 0; i--)
{
//var rankName = forwardRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Player.PlayerName;
var fw = forwardRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
var tf = tallForwardRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
var off = offensiveRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
var def = defensiveRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
var ob = onBallerRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
var ruck = ruckRank.First(x => x.Player.PlayerName == playerList[i].PlayerName).Rank;
if (fw >= 6 && tf >= 6 && off >= 6 && def >= 6 && ob >= 6 && ruck >= 6)
{
// Player is outside top 6 for each position so remove, and reduce permutations.
playerList.RemoveAt(i);
}
}
// Now update the playerId as this is used to join back to the array later.
var playerId = 0;
foreach (var p in playerList.OrderBy(p => p.PlayerName))
{
p.Id = playerId;
playerId = playerId + 1;
}
// Create and fill the position scores.
List<int[]> positionScoreArray = new List<int[]>();
foreach (var player in playerList.OrderBy(p => p.PlayerName))
{
// Player scored more than 0 so add to the positionScoreArray.
int[] playerScores = { player.Forward, player.TallForward, player.Offensive, player.Defensive, player.OnBaller, player.Ruck };
positionScoreArray.Add(playerScores);
}
// Players remaining in list pulled into array, ready for processing.
string[] playerNameArray = playerList.OrderBy(x => x.PlayerName).Select(p => p.PlayerName).ToArray();
// Load up the actual position scores to use in Parallel.For processing.
for (int i = 0; i < playerNameArray.Length; i++)
{
for (int j = 0; j < positionScoreArray.Count; j++)
{
if (j == 0)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.Forward;
}
if (j == 1)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.TallForward;
}
if (j == 2)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.Offensive;
}
if (j == 3)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.Defensive;
}
if (j == 4)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.OnBaller;
}
if (j == 5)
{
var player = playerList.FirstOrDefault(p => p.PlayerName == playerNameArray[i]);
if (player != null)
positionScoreArray[i][j] = player.Ruck;
}
}
}
Stopwatch parallelForEachStopWatch = new Stopwatch();
parallelForEachStopWatch.Start();
var count = 0;
var playerIds = Enumerable.Range(0, playerNameArray.Length).ToList();
var best = new { PlayerIds = new List<int>(), TeamScore = 0 };
var positions = new[] { "FW", "TF", "Off", "Def", "OB", "Ruck" };
// Thread safe the Parallel.ForEach
lock (ThreadSafeObject)
{
Parallel.ForEach(GetPermutations(playerIds, positions.Length), perm =>
{
var teamScore = 0;
var players = perm.ToList();
for (int i = 0; i < positions.Length; i++) teamScore += positionScoreArray[players[i]][i];
if (teamScore > best.TeamScore) best = new {PlayerIds = players, TeamScore = teamScore};
if (count++%100000 == 0) Debug.WriteLine($"{count - 1:n0}");
}
);
}
parallelForEachStopWatch.Stop();
TimeSpan parallelForEach = parallelForEachStopWatch.Elapsed;
Debug.WriteLine($"Parallel.ForEach (secs): {parallelForEach.Seconds}");
Debug.WriteLine($"Permutations: {count:n0}");
Debug.WriteLine($"Team Score: {best.TeamScore}");
// Track Parallel.ForEach result.
var tcTotwRequest = new TelemetryClient();
tcTotwRequest.TrackEvent($"Permutations: {count:n0} Score: {best.TeamScore} Time (sec): {parallelForEach.Seconds}");
lock (ThreadSafeObject)
{
if (best.PlayerIds.Count > 0)
{
for (int i = 0; i < positions.Length; i++)
{
// Update the playerList, marking best players with TeamOfTheWeek position.
var player = playerList.FirstOrDefault(p => p.Id == best.PlayerIds[i]);
if (player != null)
{
player.TeamOfTheWeekPosition = positions[i];
player.TeamOfTheWeekScore = best.TeamScore;
}
}
}
}
return playerList.OrderBy(p => p.PlayerName).ToList();
}
}
Source: stackoverflow.com
Related Articles
- Find max possible Total from a list of player scores across their positions
- Find all possible sequence list from single list c#
- c# Linq or code to extract groups from a single list of source data
- Find items from a list which exist in another list
- Is it possible to use Linq to get a total count of items in a list of lists?
- Generating the Shortest Regex Dynamically from a source List of Strings
- LINQ - get total count of values from nested list
- Find all the common time from List of time provided by each user
- How can I take only entries from even positions in List
- Find duplicate in a list from a reference list
- Find item from generic list
- find object from Tree or List Hierarchy
- creating Linq to sqlite dbml from DbLinq source code
- C# - How to find most frequent date from list
- How can I get the top three players and their high scores from a collection using linq and lambdas
- How can you use LINQ to cast from a collection of base class objects to a filtered list of their respective subclasses?
- Find an item from a list based on an ID
- find list elements which are similar to other list elements by 3 properties and then add value from the second one to the first
- How to find the last item from list have the same item using linq
- Filtering folders from a list when using LINQ to sort to find the oldest file
- how to find items in list that their sum is less than or equal a number
- find common DateTime from list of DateTime, if no common then find most common
- Retrieve a list of entites from CRM 2011, each with all of their related entities
- Find id from other list
- I would like to find the nearest larger papersize from a list
- Remove items from list based on another, w.r.t. positions
- How to find an element in the List from a specific index upto the end?
- Using Linq how do get a list of users and their last login from two tables
- Find distinct values from a list of object by one field only
- Code First EF: While searching database table is it possible to retrieve list of items it has in DataModel?
- Refactoring near identical linq queries where the where clause is different
- Get X random elements from table in database using Linq or lambda in C#
- How can I convert EnumerableRowCollection<string[]> to a regular string array?
- How do you use FirstOrDefault with Include?
- linq with right and left join
- Linq Get 7 days prior to given date
- Grouping the elements of an Array with the help of a bin Array
- Subsonic : Self Join , Table Alias
- c# WPF bind combobox to TPH in Entity Framework code first using LINQ
- Check String contain all elements in list using Linq and case insensitive
- Many-To-Many multi mapping in dapper
- Entity Framework 6 - ORA-00932 while joining with ToString
- Linq to Objects: Distinct + Concatenation
- How to access OrderBy clause from MethodCallExpression
- Refine Search and return List
- 500 error while deleting in LINQ
- grouping and Update Property in linq
- Linq To Sql compare Time only
- Enum to List<Object> (Id, Name)
- How do I use LINQ to Entities in Visual Basic?