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 Query
- Find max possible Total from a list of player scores across their positions
- Find all possible sequence list from single list c#
- I need to find max total of the sum of integers in Generic list using Linq
- 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?
- Get max & min from Entity Framework, in one query and with best query possible
- Generating the Shortest Regex Dynamically from a source List of Strings
- Find the Second Max in a list of values using linq c#
- LINQ - get total count of values from nested list
- Find all the common time from List of time provided by each user
- LINQ: Grouping By and Selecting from a List of objects based on max value
- LINQ get Max value from list
- Find max value of two (or more) properties in list
- How can I take only entries from even positions in List
- Max value from list that is smaller than X
- Find duplicate in a list from a reference list
- Find item from generic list
- linq to get max of nullable datetime from a list
- find object from Tree or List Hierarchy
- get a List of Max values across a list of lists
- 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?
- Select First, Last, Min, Max Value based on Time From a List of Objects
- 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
- Get MAX 5 items from a grouped List with LINQ and C#
- Linq Return List of Objects after max effective From Date
More Query from same tag
- Return input type of generic with type constraint in LINQ to Entities (EF4.1)
- Linq to XML (C#) parse XML tree with no attributes/id to object
- How can I make a more efficient Entity Framework LINQ call than a nested loop
- Is this a LINQ lazy loading problem?
- Converting List<int> to List of complex type
- linq operator like * (asterisk) in sql
- LINQ-to-SQL orderby question
- Managing LINQ to SQL .dbml model complexity
- LINQ Group By problem
- How do I Aggregate multiple IEnumerables of T
- Create a datetime with a time span of 24/7 (repeat every day)
- Help me to understand MY`Using` and `DataContext`
- LINQ - dictionary in dictionary
- How to find and remove duplicate objects in a collection using LINQ?
- LINQ 3 Inner Joins with 1 Left Outer Join
- Iterative loop to query the most occurring field
- How do I return a default value if collection is empty?
- Tracking/Querying Status Changes using SQL
- Newest price for an item in LINQ / LAMBDA
- GROUP BY LINQ ASP.NET MVC
- linq query with count
- Linq to SQL conversion...unable to add second COUNT
- Why is First() or ElementAt() on a dynamic IEnumerable awaitable?
- StreamInsight query based on holding period
- How to select records that have exactly matching column value?
- LINQ Get Distinct values and fill LIST
- Parsing two consecutive records in XML file
- Linq to SQL inheritance patterns
- How to call multiple actions in View in ASP.NET MVC?
- LINQ and subqueries