score:1

Accepted answer

You are close to achieve what you want. Here is my take on what I believe you are trying to do.

If the amount of data is small it doesn't matter that you are using GroupBy multiple times but it might be better to create the groups only once:

var groupings = allData
    .GroupBy(
        score => score.Player,
        (player, scores) => new
        {
            Player = player,
            Scores = scores.ToList() 
        })
    .ToList();

Calling ToList will ensure that the collection of scores for each player are enumerated and allocated into lists.

I'm not sure about the part where you determine the minimum number of records. It looks odd to compute the minimum of the Player property which I assume is the name of the player.

Here I compute the minimum number of scores for all players:

var minScoreCount = groupings.Min(grouping => grouping.Scores.Count);

In the last part you have to use Take(minScoreCount) to only take the first N scores for each player. I think this is the part that you are missing in your own code.

var sumData = groupings.Select(grouping => new Score
{
    Player = grouping.Player,
    Points = grouping.Scores
        .OrderByDescending(score => score.Points)
        .Take(minScoreCount)
        .Sum(score => score.Points),
    Strokes = grouping.Scores
        .OrderBy(score => score.Strokes)
        .Take(minScoreCount)
        .Sum(score => score.Strokes)
}).ToList();

If you didn't have the requirement to sort the scores differently for Points and Strokes you could sort the scores before the ToList inside the GroupBy reducing the number of times the code is traversing the lists of scores.

score:1

Not sure how pretty it is, but here you go. You can do it like this:

[ActionName("List")]
public async Task<IActionResult> List()
{
    var allData = await _cosmosDbService.GetScoresAsync(
        "SELECT * FROM c");
    var playerRounds = allData.GroupBy(l => l.Player);
    var minRounds = playerRounds.Min(x => x.Count());

    var sumData = playerRounds.Select(cl => new Score
    {
        Player = cl.First().Player,
        Points = cl.OrderByDescending(x => x.Points).Take(minRounds).Sum(c => c.Points),
        Strokes = cl.OrderByDescending(x => x.Points).Take(minRounds).Sum(c => c.Points),
    }).ToList();

    return View(sumData);
}

https://dotnetfiddle.net/ho1psw


Related Articles