I have a problem to order a list after a certain condition. The situation is that i build a Competition application for Range shooting and when i am about to order the list of results there is on condition i dont know how to handle with OrderBy().
This is the classes i work with, simplified to only include properties important for this question, and the Shot class is no point in showing here. I have a List of ShooterSignup
that i work with and try to order:
ShooterSignup
public class ShooterSignup
{
public List<Serie> Series { get; set;}
}
Serie
public class Serie
{
public List<Shot> Shots { get; set;}
}
The Conditions i have to order the results by are:
- Total score of all series
- Number of Center hits
These two OrderBy are straight forward and no problem. But the next OrderBy step is where i cant get it to work. The next step to order by is:
- Highest score on last Serie
- Highest score on next to last serie
- Highest score on the one before that one
- ......
and so on for the number of series shot this competition. How can i achive this orderby? Is it even possible?
Edit: This is done in a query to entity framework, so i cant use any methods created on the classes themselves since entity framework will not know how to translate that into a stored procedure
CodePudding user response:
Let the classes are defined as follows:
public class ShooterSignup
{
public List<Serie> Series { get; set; }
public int GetTotalScore()
{
return Series.Sum(serie => serie.GetScore());
}
public int GetCenterHits()
{
return Series.Sum(serie => serie.GetCenterHits());
}
}
public class Serie
{
public List<Shot> Shots { get; set; }
public int GetScore()
{
return Shots.Sum(shot => shot.Score);
}
public int GetCenterHits()
{
// assume that center hit is a hit with score = 10
return Shots.Count(shot => shot.Score == 10);
}
}
public class Shot
{
public Shot(int score)
{
Score = score;
}
public int Score { get; set; }
}
You can define series-wise comparer like this:
Comparer<ShooterSignup> seriesComparer = Comparer<ShooterSignup>.Create((a, b) =>
{
using (var enumeratorA = Enumerable.Reverse(a.Series).GetEnumerator())
using (var enumeratorB = Enumerable.Reverse(b.Series).GetEnumerator())
{
bool moveNextA = enumeratorA.MoveNext();
bool moveNextB = enumeratorB.MoveNext();
while (moveNextA && moveNextB)
{
int scoreA = enumeratorA.Current.GetScore();
int scoreB = enumeratorB.Current.GetScore();
if (scoreA != scoreB)
{
return scoreB - scoreA;
}
moveNextA = enumeratorA.MoveNext();
moveNextB = enumeratorB.MoveNext();
}
if (!moveNextA && !moveNextB)
{
return 0;
}
return moveNextA ? 1 : -1;
}
});
Now your can sort list of ShooterSignup
:
var orderedSignups = signups
.OrderBy(s => s.GetTotalScore())
.ThenBy(s => s.GetCenterHits())
.ThenBy(s => s, seriesComparer)
.ToList();