Home > Software engineering >  Accessing Linq Group Elements without iteration
Accessing Linq Group Elements without iteration

Time:11-08

Suppose I have the following classes

public class Student
{
    public int Id {get; set;}
    public int ClassId {get; set;}
    public string ClassName {get; set;}
    public string Name {get; set;}
    public int Age {get; set;}
}

public class StudentDTO
{

    public string Name {get; set;}
    public int Age {get; set;}
}

public class ClassStudent
{

    public string ClassName {get; set;}
    public List<StudentDTO> StudentDTOs {get; set;}
}

and I have a var listOfStudents = new List<Student>();

Now I enetered values into listOfStudents and grouped the according to ClassId as follows:

listOfStudents = listOfStudents.GroupedBy(l => l.ClassId).ToList();

I want the output to be a list of type ClassStudent that each group of listOfStudents is an element of this list

I am implementing it as follows:

listOfStudents.Foreach(s => 
{
    var classStudents = listOfStudents.Where(ls => ls.ClassId == s.Key).ToList();
    
    classes.Add(new ClassStudents 
    {
        ClassName = classStudents.FirstOrDefault().ClassName,
        StudentDTOs = classStudents.Select(ls => new StudentDTO
        {
            Name = ls.Name,
            Age = ls.Age
        }).ToList()
    });
});

As you notice in my approach, Grouping Element is no longer of any effect, because I still had to resort to a foreach and where elements to fill the classes.

So I can simple do as follows instead

var classIds = listOfStudents.Select(l => l.ClassId).Distinct().ToList();

foreach(int id in classIds)
{...}

Basically, grouping is meaningless here

Is their a way to avoid the foreach and access the elements directly inside the groups?

Ideally something like this:

classes = listOfStudents.Select(g => new ClassStudent
{
    ClassName = g.Elements.FirstOrDefault().ClassName,
    StudentDTOs = g.Elements.Select(ls => new StudentDTO
    {
        Name = ls.Name,
        Age = ls.Age
    }).ToList()  
});

CodePudding user response:

Better to add ClassName to grouping key. Leaving ClassId in grouping key if ClassName is not unique:

var classes = listOfStudents
    .GroupBy(s => new { s.ClassId, s.ClassName})
    .Select(g => new ClassStudents 
    {
        ClassName = g.Key.ClassName,
        StudentDTOs = g.Select(ls => new StudentDTO
        {
            Name = ls.Name,
            Age = ls.Age
        }).ToList()
    })
    .ToList();
  • Related