如何对列表列表进行分组并将其合并为单个列表,而无需在C#中重复? [英] How To group by a list of list and merge it into single list without repetition in C#?

查看:332
本文介绍了如何对列表列表进行分组并将其合并为单个列表,而无需在C#中重复?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为"studentdetails"的类和一个名为"students"的属性,这是"studentdetails"的列表.

I have a class named studentdetails and a property named students which is the list of studentdetails.

public class studentdetails 
{
    public int SubjectId  {get ; set; }
    public int studentId  { get; set; } 
    public int ClassId  { get; set; }     
}

List<studentdetails> students = new List<studentdetails>()
{ 
    new studentdetails() { studentId = 1, SubjectId = 1, ClassId = 1 },
    new studentdetails() { studentId = 2, SubjectId = 2, ClassId = 1 },
    new studentdetails() { studentId = 3, SubjectId = 1, ClassId = 2 },
    new studentdetails() { studentId = 1, SubjectId = 3, ClassId = 2 },
    new studentdetails() { studentId = 1, SubjectId = 3, ClassId = 1 }
};

我必须创建一个包含学生列表(其中包含sbject作为属性的列表)作为属性的班级列表,而不必重复班级,学生和主题(如果已经存在的话).

I have to create a list of class which contains list of student(which contains a list of sbject as property ) as a property without repeating class,student and subject if its already exist.

示例:

public class Class
{
    public int ClassId  { get; set; }
    public Lits<student> students  { get; set; }
}
public class student
{
    public int StudentId  { get; set; }
    public Lits<Subject> subjects  { get; set; }
}
public class Subject 
{
    public int SubjectId   { get; set; }
}

例如: 与参考上面的学生详细信息

For Example: With refer to above studentdetails

class(1) -student(1) -subject(1)
                     -subject(3)
         -student(2) -subject(2)

class(2) -student(3) -subject(1)
         -student(1) -subject(3)

推荐答案

下一种方法可以用来解决问题:

The next approach can be used to solve the problem:

List<Class> classes = students
    // This GroupBy creates groups by ClassId:
    // (ClassId) -> (List of Students).
    .GroupBy(s => s.ClassId)
    .Select(c => new Class
    {
       ClassId = c.Key,
       Students = c
          // This GroupBy for given Class creates groups by StudentId:
          // (StudentId) -> (List of Subjects).
          .GroupBy(s => s.StudentId)
          .Select(s => new Student
          {
             StudentId = s.Key,
             Subjects = s
                // This GroupBy for given Class and Student removes
                // duplicate values of SubjectId. If you can guarantee
                // that for given Class and Student will not be duplicate
                // values of SubjectId then you can remove this GroupBy.
                // If you remove this GroupBy then you need to change 
                // expression inside Select to the following:
                // new Subject { SubjectId = t.SubjectId }.
                .GroupBy(t => t.SubjectId)
                .Select(t => new Subject { SubjectId = t.Key })
                .ToList()
          }).ToList()
    }).ToList();

以下是完整示例,展示了这种方法.

Here is complete sample that shows this approach.

@Thaks在评论中问:

@Thaks asked in the comment:

如果有班级名称,学生姓名和活动名称以及ID. 那么我该如何相应地映射到实例?

If there is class name, student name and aсtivity name along with ids. Then how can I map accordingly to the instance?

如果还需要映射除id之外的其他属性,则应使用GroupBy方法的下一个重载:

If you need additionally to map properties other then id then you should use the next overload of GroupBy method: GroupBy(keySelector, comparer). Using this method we can use instances of StudentDetails class as keys and specify comparer for them.

首先,我们应该创建comparer,该类实现接口

At first we should create comparer, a class that implements interface IEqualityComparer. In our sample we can use a single comparer class to perform all three GroupBy operations, because all our GroupBy operations are performed using int Id property. Typically each GroupBy operation uses its own comparer class because most of the time different GroupBy operations are performed using different keys (different data types, different number of groupping properties). Here is how we can implement our comparer:

// For demo I simplified implementation of the Equals and GetHashCode
// methods by excluding null checks. In the documentation of 
// IEqualityComparer you can find implementation with null checks.
public class ComparerById<T> : IEqualityComparer<T>
{
    private readonly Func<T, int> _keySelector;

    public ComparerById(Func<T, int> keySelector) => _keySelector = keySelector;

    public bool Equals(T x, T y) => _keySelector(x) == _keySelector(y);

    public int GetHashCode(T obj) => _keySelector(obj);
}

然后使用此comparer我们可以执行所需的GroupBy:

And then using this comparer we can perform required GroupBy:

List<Class> classes = students
    // Now key of each group has type StudentDetails, therefore later we
    // will be able to use properties of StudentDetails such as ClassName.
    // Here to compare keys of type StudentDetails we use comparer:
    // new ComparerById<StudentDetails>(s => s.ClassId);
    // It means that we create groups by ClassId.
    .GroupBy(s => s, new ComparerById<StudentDetails>(s => s.ClassId))
    .Select(c => new Class
    {
        ClassId = c.Key.ClassId,
        ClassName = c.Key.ClassName,
        Students = c
            // Here we create groups by StudentId.
            .GroupBy(s => s, new ComparerById<StudentDetails>(s => s.StudentId))
            .Select(s => new Student
            {
                StudentId = s.Key.StudentId,
                StudentName = s.Key.StudentName,
                Subjects = s
                    // Here we create groups by SubjectId.
                    .GroupBy(t => t, new ComparerById<StudentDetails>(t => t.SubjectId))
                    .Select(t => new Subject {SubjectId = t.Key.SubjectId, SubjectName = t.Key.SubjectName})
                    .ToList()
            }).ToList()
    }).ToList();

这里是完整的示例,显示了这种方法.

Here is complete sample that shows this approach.

这篇关于如何对列表列表进行分组并将其合并为单个列表,而无需在C#中重复?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆