Reputation: 174
I'm trying to order a list of players for a turn based game and i have the following data structure:
public class PlayerTurn {
public int energy;
public int team; //Can be 0 or 1
}
public List<PlayerTurn> turnList = new List<PlayerTurn>();
Let's say that we have 4 players, 2 on each team like this:
Player | Energy | Team |
---|---|---|
Player 1 | 10 | 0 |
Player 2 | 30 | 0 |
Player 3 | 5 | 1 |
Player 4 | 60 | 1 |
How i can order this list in a way that the player with most energy will be first, but alternating between the teams while keeping the order by energy? The result expected is something like:
Player | Energy | Team |
---|---|---|
Player 4 | 60 | 1 |
Player 2 | 30 | 0 |
Player 3 | 5 | 1 |
Player 1 | 10 | 0 |
Is possible to achieve that only with Linq? Without using Linq is also acceptable.
EDIT: Here's the link with a test of two approaches by @GianPaolo and @VadimMartynov https://dotnetfiddle.net/0O22dX
Upvotes: 0
Views: 163
Reputation: 8902
OrderByDescending
.GroupBy
. After that you will have 2 ordered groups for each team.teamIndex
as an index of team and playerIndex
as a players index inside their team. We create a new objects for each player with 3 properties: player himself, team (group) index, player index. Here we use anonymous types to create an object without type declaration.OrderBy
.ThenBy
.Select
.var result = turnList
.OrderByDescending(p => p.energy)
.GroupBy(p => p.team)
.SelectMany((team, teamIndex) => team
.Select((player, playerIndex) => new { player, teamIndex, playerIndex }))
.OrderBy(item => item.playerIndex)
.ThenBy(item => item.teamIndex)
.Select(item => item.player)
.ToList();
It's important to use teamIndex
in the step 3 because team with the best player always be in [0]
-th place in a grouped list because we ordered all players in the step 1 first.
Upvotes: 2
Reputation: 4249
I'd go splitting the list in two, one for each team. then sort both of them and then, very old style, pick one element at time from each list
List<PlayerTurn> allPlayers = new List<PlayerTurn>();// populated somehow
List<PlayerTurn> teamOne = allPlayer.Where (p=> p.Team = 1).OrderByDescending(p=>p.energy).ToList();
List<PlayerTurn> teamZero = allPlayer.Where (p=> p.Team = 0).OrderByDescending(p=>p.energy).ToList();
// which team go first?
var firstTeam = teamOne[0].energy >= teamZero[0].energy ? teamOne : teamZero;
var secondTeam = firstTeam == teamZero ? teamOne : teamZero;
var sorted = new List<PlayerTurn>();
// now zip the two teams
for (int i = 0; i < teamOne.Count(); i++) // TODO: check lists are same length
{
sorted.Add(firstTeam [i]);
sorted.Add(secondTeam [i]);
}
return sorted;
Upvotes: 2