culdaffe
culdaffe

Reputation: 39

Is there a way to use Linq to display an item with the highest result without duplication of a specific name?

I am trying to add a feature to my website where the teacher can see a summary of students who have completed goals that week. This is my controller method

public IActionResult WeeklyDetails()
        {
            var user = svc.GetUser(GetSignedInUserId());
           
            var goals = svc.GetGoalsForTeacher(user.Id);
            

            var mostRecentMonday = DateTime.Now.StartOfWeek(DayOfWeek.Monday);//get week start of most recent Monday morning
            var weekEnd = mostRecentMonday.AddDays(7).AddSeconds(-1); //will return the end of the day on Sunday


            var results = goals.Where(g => g.AchievedOn >= mostRecentMonday && g.AchievedOn <= weekEnd).ToList();
            for (int i = 0; i < results.Count; i++)
            {
                //Get count of current element to before:
                int count = results.Take(i + 1)
                                .Count(r => r.Student.Name == results[i].Student.Name);
                results[i].Count = count;
            }


       
            var result = results.GroupBy(x => x.Id)
                                .Select(group => group.First()).ToList();     
           
            return View(result);


        }

In my cshtml view page I call the details like this

 @foreach(var item in Model)
{
    <p>@item.Student.Name @item.Count</p>
}

However, I achieve this result

Emma 1

Emma 2

Sarah 1

This is because emma has two goals which are completed in the list I know, however I would prefer for Emma 2 to be the only result that is shown. Is there a way to choose Max and then the first? Maybe not, my apologies if this is unclear.

Upvotes: 0

Views: 35

Answers (1)

Michael
Michael

Reputation: 1276

I don't know the definition of result, but I think you group by the primary key of result (x.Id). You use the original result list as model of your view. But you provide aggregated data, so I would create a clean type (can be done inside your controller class as nested class):

public class GoalSummary
{
    public int StudentId {get;set;}
    public string Firstname {get;set;}
    public string Name {get;set;}
    public int Goals {get;set;}
}

Then you can use grouping and projecting (select) to create this results:

var summary = goals
    .Where(g => g.AchievedOn >= mostRecentMonday && g.AchievedOn <= weekEnd)
    .GroupBy(g => new {g.Student.Id, g.Student.Firstname, g.Student.Name})
    .Select(g => new GoalSummary
    {
        StudentId =  g.Key.Id,
        Firstname = g.Key.Firstname,
        Name = g.Key.Name,
        Goals = g.Count()
    }).ToList();
return View(summary);

If you are familiar with SQL: We want StudentId, Firstname, Name and COUNT(*). So we have to group by Id, Firstname and Name.

In your View you can use your typed summary:

@model List<YourNamespace.Controllers.YourController.GoalSummary>

Upvotes: 1

Related Questions