如何通过集合来分组,成为集合的Enumerable。

问题描述 投票:0回答:1

我有一个实现以下属性的集合.这里是一个例子。

class Student {public string Name, public string Subject, public double Grade }

在自定义查询之后,我有一个学生的集合作为返回值

IEnumerable<Student> studentList

它有多个项目的所有学生信息与重复的名称如下内容。

[Charla, English, 92][Charla, Math, 64][Sherry, English, 91][Sherry, Math, 70]

我想实现一个linq查询,以组这个列表的名称和返回。

IEnumerable<Name, IEnumerable<Student>> studentListGropByName

夏拉:【夏拉,英语,92】【夏拉,数学,64】。

Sherry: [雪莉,英语,91] [雪莉,数学,70]

其他名称:...

有没有什么可能的查询来实现?

c# linq
1个回答
1
投票

考虑使用一个重载的 GroupBy.

使用 GroupBy,您可以创建学生组,其中同一组中的所有学生都具有一个或多个属性的相同值。这个相同的值被称为 Key。

GroupBy 的参数之一是 KeySelector。这个参数定义了一个组中所有学生应该具有的共同属性值。

哟要制作学生组,组中每个键为 "X "的学生的属性值Student.Name等于 "X"。

IEnumerable<Student> ungroupedStudents = ...

IEnumerable<IGrouping<string, Student> studentsGroupedByName = ungroupedStudents.GroupBy(

    // KeySelector: make groups of students with same name:
    student => student.Name);

这就形成了一个组的序列 每个Group都有一个字符串属性Key,它是该组中所有学生的共同名称。该组也是一个学生序列(要注意:是IS不是HAS)。组中的每个学生都有相同的Student.Name的值,即Key的值。

这看起来几乎就像你想实现的那样。你的代码的大多数读者都会知道GroupBy,他们期待一个IGrouping。所以考虑使用这个作为结果。

然而,如果你真的想要一个对象序列,其中每个对象都有一个字符串属性Name和一个属性Students,可以考虑使用GroupBy的其他重载,一个有参数resultSelector的重载。

var studentsGroupedByName = ungroupedStudents.GroupBy(

    // keySelector: make groups of students with same name:
    student => student.Name,

    // resultSelector: from every common name, and all students with this name
    // make one new object:
    (commonName, studentsWithThisName) => new
    {
        Name = commonName,
        Students = studentsWithThisName,
    })

这将给你你想要的东西。然而,它的效率并不高:学生组 "Charla "有25个元素,而名字 "Charla "有26次。最好不要重复选择这个名字。

// resultSelector
(commonName, studentsWithThisName) => new
{
    Name = commonName,
    Grades = studentsWithThisName.Select(student => new
    {
        Subject = student.Subject,
        Grade = student.Grade,
    }
    .ToList()
}

现在你真的有了一个学生和他们的等级的序列。

你的数据库没有标准化

你确定学生的名字是独一无二的吗?您的收藏中不会有两个叫 "John Doe "的学生?如果您在开发阶段仍然可以更改学生,请考虑给每个学生一个唯一的ID,类似于数据库中的情况。

如果您将在较长的时间内使用这种设计,并将创建大量的学生和年级,将您的数据分割成几个表将使您在未来的工作中避免很多麻烦,如果您已经有数千名学生的成绩,而您突然得到一个新的学生,而他的名字已经存在。这也会使人们不太可能犯打字错误("Mash "而不是 "Math"),即使他们犯了错误,也只需要在一个地方改变。

我也觉得用双数来表示 "Grade "有问题。最好使用十进制。如果你确定Grade在小数点后的位数有限,那么在平等比较中,小数比双数要好得多。所以,如果你需要得到等级等于4.7的学生,小数是更好的方法,特别是如果你使用计算来得到这个值。

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

public class Grades
{
    public int Id {get; set;}
    public decimal Grade {get; set;}
    ... // other properties, for example
    public DateTime Date {get; set;}

    // foreign keys
    public int StudentId {get; set;}
    public int SubjectId {get; set;}
}

public class Subject
{
    public int Id {get; set;}
    public string Name {get; set;}
    ... // other properties, for instance:
    public string description {get; set;}
}
© www.soinside.com 2019 - 2024. All rights reserved.