Skip to content

Latest commit

 

History

History
195 lines (137 loc) · 9.3 KB

File metadata and controls

195 lines (137 loc) · 9.3 KB

十四、分组汇总结果

在本章中,我们将讨论如何使用 LINQ 对相关结果进行分组。 分组是在数据库中对结果进行分类的一项基本工作。

向 HTML 添加一个 Show Results 按钮

提出一个项目。 首先,我们将在 HTML 中放入一个按钮,显示结果; 要做到这一点,在以<form id=....开头的行下面放置一个按钮:

<asp:Button ID="Button1" runat="server" Text="Show Results" /<br />

接下来,切换到 Design 视图并双击 Show Results 按钮。 这把我们带入了Default.aspx.cs。 删除Page_Load块。 这个项目开始代码的相关部分应该类似于图 14.9.1:

Figure 14.9.1: The starting code section for this project

添加名称空间

首先,我们需要添加两个名称空间。 为此,在文件顶部附近的using System下输入以下内容:

using System.Linq;
using System.Collections.Generic;

创建学生类并定义字段

接下来,我们将制作一个名为Student的类。 在以public partial class _Default...开头的行之上,输入以下内容:

public class Student

接下来,要定义字段,在这一行下面的一组花括号之间输入以下内容:

public string Name { get; set; }

这里有一些性质,然后再加一个。 在这一行下面输入以下内容:

public List<int> Grades;

这里的List<int>是学生的成绩,我们将其命名为Grades

列出学生的名单

现在,在下一阶段,我们将列出学生名单。 要做到这一点,首先在以protected void Button1_Click...开头的行后面的花括号之间输入以下内容:

List<Student> students = new List<Student>

这里,students是列表的名称。 然后我们有了一个新的学生名单。 接下来,为了初始化列表,我们将把所有的新学生放在这一行下面的一组花括号之间,如下所示:

new Student {Name="Smith, John", Grades=new List<int> {78,98,67,87 } },

在前面一行中,在new Student之后,您将每个学生的所有信息单独放在一组花括号中。 首先,您需要定义Name的价值,所以你设置等于Smith,John比如,插入一个逗号,然后把约翰的Grades一个新的整数列表,设置这些值78,98,67、【显示】。

接下来,我们需要为其他学生重复几次; 所以,复制这一行并粘贴到下面。 编辑这一行,将变量Name的值更改为AdamsAmy,将等级更改为91998993:

new Student {Name="Adams, Amy", Grades=new List<int> {91,99,89,93 } },

This level of coding is very practical and realistic. Having done coding for five years, I can tell you that things are always far more interesting and more challenging.

现在,再重复一遍这个过程。 复制前面的行并粘贴到下面。 编辑这一行,将变量Name的值更改为SmithMary,将等级更改为89878488。 请确保在最后一个new Student类后面的下一行插入一个闭花括号和一个分号:

new Student {Name="Smith, Mary", Grades=new List<int> {89,87,84,88 }};

分组名称

同样,因为我们想要分组,例如,根据姓氏和名,这就是为什么我使用了两个相同的姓氏。 我们将根据姓氏很好地分组显示结果; 也就是说,先按姓氏的第一个字母,然后再按姓氏。

接下来,我们将编写 LINQ 查询来完成分组。 同样,这可以用一种更复杂的方法来完成,但这是一个相对简单的例子。 因此,在列表中最后一个new Student类后面的一行的右花括号和分号下面,输入以下内容:

var groupsByFirstLetters = from student in students group student by student.Name[0];

记住,groupsByFirstLetters表示姓氏的第一个字母。 所以,要写这个查询,你在students中写上fromstudent,然后在下一行中写上group,然后在student.Name中写上group。 因为Name是一个字符串,所以您可以使用方括号提取第一个字符,然后获取字符串中索引0的值。 这就是为什么你可以这样写。 否则,这就显得有点神秘了。

显示分组结果

现在,要以分组方式显示结果,必须使用嵌套的foreach循环。 因此,输入以下内容:

foreach(var studentGroup in groupsByFirstLetters)

这里,它变得更有趣了。 如果您将鼠标悬停在var上,它将告诉您var代表什么。 它说,这是一组人物和学生。 它表示具有公共键的对象集合。

现在,我们可以这样利用它。 在前一行下面的一组花括号之间输入以下内容:

sampLabel.Text += $"<br>{studentGroup.Key}";

首先,我们想要显示关键字,即每个姓氏的第一个字母,然后所有内容将被总结在该姓氏的第一个字母下。 所以我们说studentGroup.Key。 对于每个组,有一个名为Key的属性,它是分组的关键。 记住这里我们是根据姓氏的第一个字母来分组的。 关键是这个量。

接下来,一旦你确定了组中的第一个字母,通常有几个学生或几个项目,对吗? 所以,现在你必须分别显示这些项目。 接下来输入以下内容:

foreach(var st in studentGroup)

注意这里关于foreach循环的嵌套。 您看到在foreach (var studentGroup in groupsByFirstLetters)行中,外部的for循环获得studentGroup变量,然后sampLabel.Text += $"<br>{studentGroup.Key}"行显示该组的键了吗? 好了,接下来你会仔细观察每个小组里的学生。 这就是为什么在下一个阶段中,如果您将鼠标悬停在前面一行中的var上,您会看到它显示studentGroup中的student st。 那么,这就是分解。

接下来,要显示它,在前面的foreach行下的一组花括号中输入以下内容:

sampLabel.Text += $"<br>{st.Name}";

这是它的核心。 现在记住,我们从一个叫做Student的课程开始。 然后我们有一份学生名单。 注意,在学生列表中,您还可以使用一种语法,该语法表示属性的名称,然后表示不带圆括号的属性值。 您可以只使用花括号将对象直接放在学生列表的定义中。

var groupsByFirstLetters...开头的块为我们分组。 然后我们需要外部循环foreach (var studentGroup...来显示每个组的键。 然后内部的foreach循环foreach (var st in studentGroup)显示该组中的学生。 所以,这两个循环是必需的,它们的目的不同。

现在在浏览器中打开它,看看结果。 单击 Show Results 按钮。 如你所见,在图 14.9.2 中,你有字母 S,这是第一组的键,在这组中你有 Smith, John,然后是 Smith, Mary。 接下来是字母 A,这是第二组的关键,其中有亚当斯,艾米:

Figure 14.9.2: The results of running the program for this chapter

当然,这是可以排序的,其他的事情也可以做。 然而,这些只是基础。 所以,你知道这是可行的; 许多更复杂的事情是可能的。

章回顾

为了便于审阅,本章的Default.aspx.cs文件的完整版本,包括注释,如下代码块所示:

//using is a directive
//System is a name space
//name space is a collection of features that our needs to run
using System;
using System.Linq;
using System.Collections.Generic;
//public means accessible anywhere
//partial means this class is split over multiple files
//class is a keyword and think of it as the outermost level of grouping
//:System.Web.UI.Page means our page inherits the features of a Page
public class Student //define student class
{
    public string Name { get; set; }
    public List<int> Grades;
}
public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        //create list of students
        List<Student> students = new List<Student>
        {
            new Student {Name="Smith, John", 
            Grades=new List<int> {78,98,67,87}},
            new Student {Name="Adams, Amy", 
            Grades=new List<int> {91,99,89,93}},
            new Student {Name="Smith, Mary", 
            Grades=new List<int> {89,87,84,88}}
        };
        //create query that groups students by first letter of last name
        //Name is a string, so student.Name[0] means grab the 
        //first character for grouping
        var groupsByFirstLetters = 
        from student in students group student by student.Name[0];
        //the outer loop is needed to display the "Key", 
        //which is the first letter for each group
        foreach(var studentGroup in groupsByFirstLetters)
        {
            sampLabel.Text += $"<br>{studentGroup.Key}";
            //the inner loop is needed to display the students 
            //within each group
            foreach(var st in studentGroup)
            {
                sampLabel.Text += $"<br>{st.Name}";
            }
        }
    }
}

总结

在本章中,我们讨论了如何使用 LINQ 对相关结果进行分组。 您创建了一个学生类并定义了字段,创建了一个学生列表、分组的名称,最后显示分组的结果。

在下一章中,您将学习如何使用 LINQ 编写连接不同结果集或不同数据集的查询。