4. group子句
根据语法规则,LINQ表达式必须以from子句开头,以select或group子句结束,所以除了使用select子句外,也可以使用guoup子句来返回元素分组后的结果。group子句返回的是一个IGrouping<TKey,TElement>泛型接口的对象集合,下面先了解下这个接口。
4.1 IGrouping<TKey,TElement>泛型接口
这个接口表示具有公共键的对象集合,它的原型如下:
public interface IGrouping<TKey, TElement> : IEnumerable<TElement>,
IEnumerable
TKey是键的对象类型,在用于group子句的时候,数据类型会有编译器推断出来,它一般用于存储分组的键值;TElement是指的对象类型,用于存储分组的结果,变量基于这个接口的类型就是遍历这个值。
4.2 分组查询
分组查询对于关系型数据库是非常常见的一种操作,但在没有LINQ之前,对内存的对象进行分组却是一件非常麻烦的事情。现在,在LINQ表达式中只需要使用group子句就可以轻松完成对内存对象的分组。
List<CustomerInfo> clist = new List<CustomerInfo>
{
new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},
new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},
new CustomerInfo{ Name="欧阳锦鹏", Age=35, Tel ="1330708****"},
new CustomerInfo{ Name="上官无忌", Age=23, Tel ="1380524****"}
};
//按照名字的前2个字进行分组
var query = from customer in clist
group customer by customer.Name.Substring(0, 2);
foreach (IGrouping<string,CustomerInfo> group in query)
{
Console.WriteLine("分组键:{0}",group.Key);
foreach (var ci in group)
{
Console.WriteLine("姓名:{0} 电话:{1}", ci.Name, ci.Tel);
}
Console.WriteLine("***************************************");
}
//分组键:欧阳
//姓名:欧阳晓晓 电话:1330708****
//姓名:欧阳锦鹏 电话:1330708****
//***************************************
//分组键:上官
//姓名:上官飘飘 电话:1592842****
//姓名:上官无忌 电话:1380524****
//***************************************
上例代码,按照form子句建立的范围变量customer的Name属性的前两个字作为键值进行分组。所以TKey的类型是一个字符串类型。
//按照年龄是否大于20分组
var query = from customer in clist
group customer by customer.Age > 20;
foreach (var group in query)
{
Console.WriteLine("分组键:{0}",group.Key);
foreach (var ci in group)
{
Console.WriteLine("姓名:{0} 电话:{1}", ci.Name, ci.Tel);
}
Console.WriteLine("***************************************");
}
//分组键:True
//姓名:欧阳晓晓 电话:1330708****
//姓名:欧阳锦鹏 电话:1330708****
//姓名:上官无忌 电话:1380524****
//***************************************
//分组键:False
//姓名:上官飘飘 电话:1592842****
//***************************************
group子句用了一个布尔表达式,所以IGrouping<TKey,TElement>的TKey变成了一个bool型。并且循环遍历的时候可以用var代替IGrouping的声明:
5. into子句
into子句作为一个临时标识符,用于select,group,join子句中。
List<CustomerInfo> clist = new List<CustomerInfo>
{
new CustomerInfo{ Name="欧阳晓晓", Age=35, Tel ="1330708****"},
new CustomerInfo{ Name="上官飘飘", Age=17, Tel ="1592842****"},
new CustomerInfo{ Name="欧阳锦鹏", Age=35, Tel ="1330708****"},
new CustomerInfo{ Name="上官无忌", Age=23, Tel ="1380524****"}
};
//按照名字的前两个字进行分组,再用分组Key进行排序
var query = from customer in clist
group customer by customer.Name.Substring(0, 2) into gpcustomer
orderby gpcustomer.Key descending
select gpcustomer;
Console.WriteLine("into 用于group子句");
foreach (var group in query)
{
Console.WriteLine("分组键:{0}", group.Key);
foreach (var ci in group)
{
Console.WriteLine("姓名:{0} 电话:{1}", ci.Name, ci.Tel);
}
Console.WriteLine("***************************************");
}
var query2 = from customer in clist
select new { NewName = customer.Name, NewAge = customer.Age } into newCustomer
orderby newCustomer.NewAge
select newCustomer;
Console.WriteLine("into 用于select子句");
foreach (var ci in query2)
{
Console.WriteLine("{0} 年龄:{1}", ci.NewName, ci.NewAge);
}
//into 用于group子句
//分组键:上官
//姓名:上官飘飘 电话:1592842****
//姓名:上官无忌 电话:1380524****
//***************************************
//分组键:欧阳
//姓名:欧阳晓晓 电话:1330708****
//姓名:欧阳锦鹏 电话:1330708****
//***************************************
//into 用于select子句
//上官飘飘 年龄:17
//上官无忌 年龄:23
//欧阳晓晓 年龄:35
//欧阳锦鹏 年龄:35
into子句提供了一个临时标识符,它存储了into子句前面的查询内容,使它后面的子句可以方便的使用,对其进行再次查询,投影等操作。