LINQ
4月3
[codes=c#]
using System;
using System.Collections.Generic;
using System.Collections ;
using System.Linq;
using System.Text;
namespace LINQ技术
{
class LINQ查询操作符
{
public static void Main()
{
//首先,我们先列出Linq一些常用的操作符
// Where 与 OfType Where是条件过滤,可以根据为此,其实就是一个委托,返回一个布尔。根据这个委托来实现过滤
// OfType是根据类型来过滤,他只返回Tresult类型的元素
// 11.2.1过滤
IEnumerable list1 = GetMyList();
var query1 = from p in list1 where p.age >= 20 select p;
Console.WriteLine("-----------------过滤:大于等于20岁的人员-------------");
PrintMyInfo(query1);
//下面我们写一个对象查询的版本
Console.WriteLine("-----------------过滤:大于等于30岁的人员(对象版本)-------------");
list1 = list1.Where(par => { return par.age >= 30; }).Select(par => par);
PrintMyInfo(list1);
// 11.2.2 用索引来过滤
//这是一个无法使用LINQ语句来实现的功能,他是Where方法的重载
//在这个方法中,可以传入第二个参数---索引
//可以是过滤器返回个数的计数器,可以在表达式中使用这个索引,执行基于索引的计算。
//public delegate TResult Func(T1 arg1, T2 arg2); 委托重载
IEnumerable list2 = GetMyList();
list2 = list2.Where((p1, p2) => p1.name.StartsWith("a") && p2 <= 1);
Console.WriteLine("-------------基于索引过滤:姓名以A开头,只要2名,多了不要-------------");
PrintMyInfo(list2);
// 11.2.3 类型过滤
//假定一个数组包含有整型,与字符型元素,而我们只想过滤出字符型元素。呵呵,这么怪的东西,一般是没有啦
object[] objs = new object[] { 232, 23, 3232, "aladdin", 332, 32323, "fuck" };
var query2 = objs.OfType();
Console.WriteLine("-----------类型过滤,只要string型的元素---------");
foreach (string s in query2)
{
Console.WriteLine(s);
}
// 11.2.4 符合的form子句
// 如果需要根据对象的一个成员过滤,而该成员本身又是一个系列,就要用到符合子句
// 下面,我们要先出,所年龄在25以上,并且拥有一输开奔驰的牛B人物(一个人可以有多个车)。。我连个蛋蛋也没有,乃球
IEnumerable list3 = GetMyList();
Console.WriteLine("-----------复合子句,所年龄在25以上,并且拥有一输开奔驰的牛B人物---------");
var quer3 = from p in list3 from c in p.list where c.name.Equals("奔驰") where p.age >= 25 select (p);
PrintMyInfo(quer3);
//下面我们来分析一下select投影方法
//public static IEnumerable Select(this IEnumerable source, Func selector)
//Select方法定义了2个泛型类型,源,返回类型
//IEnumerable 返回可以跌代的类型
//2个参数 :this IEnumerable source 是指本方法要扩展IEnumerable类型。
// Func selector委托
// 委托的声明: public delegate TResult Func(T arg)
IEnumerable list4 = GetMyList();
var query4 = list4.Select(p => p.age);
//Select第一个参数是隐式的,所以我们不用关心,只要明白它是扩展哪个类型就可以了
//第二个参数通过源类型,返回一个投影类型,可以是源类型的一个字段,也可以将源类型直接返回,也就是我们直接写 select p
//以上示例,我们是将源类型中的age返回,它是int 型。下面我们跌代,就不可以用Person来跌代了。
Console.WriteLine("-----------按年纪投影---------");
foreach (int p in query4)
{
Console.WriteLine(p);
}
//在select与where这两个方法上,可能会存在一点误解,我开始认为select可以做与where一样的事情,下面我们证实一下
var query5 = list4.Select(p =>
{
if (p.age >= 25)
{
return new Person(p.name, p.age);
}
else
{
return new Person("node", 1);
}
});
//以上代码,我们想用select来过滤超过25岁的人,但是,无法将不需要的部分不要,所以,还是没办法做与where一样的功能
//而where方法,返回的是bool,可以筛选不合格的条件的。
Console.WriteLine("-----------select模拟 where ---------");
foreach (Person p in query5)
{
Console.WriteLine(p.name);
}
//看完了select我们接着看SelectMany方法,其实复合查询中,就是用到了这个方法。
//public static IEnumerable SelectMany(
// this IEnumerable source,
// Func> collectionSelector,
// Func resultSelector
//)
//返回IEnumerable
//3个参数,第一个是隐式的,也就是指明他扩展的是哪种类型的this IEnumerable source
//第二个参数,是一个委托 Func> collectionSelector,
//下面我们看这个委托的声明:public delegate TResult Func( T arg )
//这里与select方法有一点不同,select用委托做参数时保留了TResult类型,而这里我们指定成了IEnumerable>
//第三个参数,同样也是一个委托 Func resultSelector
//public delegate TResult Func(T1 arg1,T2 arg2)
IEnumerable list5 = GetMyList();
//以下示例是SelectMany方法的第一种重载,只是将一个序列的子集序列查出来
var query6 = list5.SelectMany(par => par.list).Where(p => p.name.Equals("奔驰"));
Console.WriteLine("查询序列的序列-------------------");
foreach (Cars car in query6)
{
Console.WriteLine(car.name);
}
//我们用对象方法的方式来查询一次所有25岁以上的拥有奔驰车的牛B人物
var query7 = list5.SelectMany(cars => cars.list, (per, car) => new { Person = per, Cars = car }).Where(p => p.Person.age >= 25 && p.Cars.name.Equals("奔驰")).Select(par => par.Person.name);
Console.WriteLine("对象方式复合查询-------------------");
foreach (var a in query7)
{
Console.WriteLine(a);
}
// 11.2.5 排序
// 下面我们写一个小例,把人按照年纪排一次序
var query8 = list5.Select(p => p).OrderBy(p => p.age).ThenBy(p => p.name);
var query9 = list5.Select(p => p).OrderByDescending(p => p.age).Take(2);
Console.WriteLine("------------升序所有人--------------");
PrintMyInfo(query8);
Console.WriteLine("降序所有人--------------------");
PrintMyInfo(query9);
// Order 与 OrderByDescending方法都是返回IOrderedEnumerable接口类型,这个接口扩展自IEnumerable
//public static IOrderedEnumerable OrderByDescending(
// this IEnumerable source,
// Func keySelector
//)
// 11.2.6 分组
//下面我们先用linq 语句实现分组查询,我们把人的年纪分组,我们只接受元素大于2个的组,每一组我们个数排,如果个数相同,我们按年纪排。
var query10 = from per in list5
group per by per.age into g
orderby g.Count(), g.Key
where g.Count() >= 2
select new { Age = g.Key, Count = g.Count() };
Console.WriteLine("--------分组查询-----------");
foreach (var a in query10)
{
Console.WriteLine(a.Age + " " + a.Count);
}
//方法方式实现上面功能
var query11 = list5.GroupBy(per => per.age)
.OrderBy(p => p.Count()).ThenBy(p => p.Key)
.Where(p => p.Count() >= 2)
.Select(p => new { Age = p.Key, Count = p.Count() });
Console.WriteLine("--------分组查询,方法方式-----------");
foreach (var a in query11)
{
Console.WriteLine(a.Age + " " + a.Count);
}
// 11.2.7 对嵌套的对象分组
//如上所示,我们将年纪分组,如果想要把组内人员的名字一并返回,势必将名字会当成一个序列,此时,它是一对多的关系
Console.WriteLine("---------嵌套对象分组-------------");
var query12 = list5.GroupBy(per => per.age)
.OrderBy(p => p.Count()).ThenBy(p => p.Key)
.Where(p => p.Count() >= 2)
.Select(p => new
{
Age = p.Key,
Count = p.Count(),
Persons = from per in p orderby per.name select per
});
foreach (var a in query12)
{
Console.WriteLine(a.Age + " " + a.Count);
foreach (var b in a.Persons)
{
Console.WriteLine(b.name);
}
}
// 11.2.8 连接
//搞不个恰当的例子吧,我们现在扩展一种类,来描述动物,同样具有名字与年纪,我们用连接,查询与动物相同年纪的人
var query13 = GetMyAnimalList().Select(animal => animal);
var query14 = GetMyList().Select(person => person);
var query15 = from per in query14
join animal in query13 on per.age equals animal.age
select new
{
DogName = animal.name,
DogAge = animal.age,
PersonName = per.name,
PersonAge = per.age
};
foreach (var v in query15)
{
Console.WriteLine("人名:{0} , 年纪{1}------动物名:{2} ,年纪{3}", v.PersonName, v.PersonAge, v.DogName, v.DogAge);
}
// 11.2.9 设置方法
//Concat(连接)
//说明:连接不同的集合,不会自动过滤相同项;延迟。
IEnumerable ani = GetMyAnimalList();
IEnumerable pers = GetMyList();
int i = 0;
var query16 = (from a in ani select a.name).Concat(from p in pers select p.name);
Console.WriteLine("--------------连接操作----------");
foreach (var str in query16)
{
++i;
Console.WriteLine(str);
}
Console.WriteLine("个数:" + i);
//可以看出,我们将所有人与动物的名字做了一个连接操作,全部显示了出,不过并没有自动过滤重复项目
//以上示例,只是连接了一个字段,下面我们复合型式连接
Console.WriteLine("--------------复合连接操作----------");
var query17 = (from a in ani select new { Name = a.name, Age = a.age })
.Concat(from p in pers select new { Name = p.name, Age = p.age });
i = 0;
foreach (var str in query17)
{
++i;
Console.WriteLine(str.Name + " " + str.Age);
}
Console.WriteLine("个数:" + i);
//Union(合并)
//说明:连接不同的集合,自动过滤相同项;延迟。即是将两个集合进行合并操作,过滤相同的项。
var query18 = (from a in ani select a.name).Union(from p in pers select p.name);
Console.WriteLine("--------------合并操作----------");
i = 0;
foreach (var str in query18)
{
Console.WriteLine(str);
++i;
}
Console.WriteLine("个数:" + i);
//可以看出,我们将所有人与动物的名字做了一个连接操作,全部显示了出,不过并没有自动过滤重复项目
//以上示例,只是连接了一个字段,下面我们复合型式连接
IEnumerable ani2 = GetMyAnimalList();
IEnumerable pers2 = GetMyList();
Console.WriteLine("--------------复合合并操作----------");
var query19 = (from a in ani2 select new { Age = a.age, Name = a.name })
.Union(from p in pers2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query19)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
//这时有一点疑问,并集比较时,没有按匿名对象,而依然是在用 name,不知道为什么
// Intersect(相交)
//说明:取相交项;延迟。即是获取不同集合的相同项(交集)。即先遍历第一个集合,找出所有唯一的元素,
//然后遍历第二个集合,并将每个元素与前面找出的元素作对比,返回所有在两个集合内都出现的元素。
Console.WriteLine("--------------相交操作----------");
var query20 = (from a in ani2 select new { Age = a.age, Name = a.name })
.Intersect(from p in pers2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query20)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
// Except(与非)
//说明:排除相交项;延迟。即是从某集合中删除与另一个集合中相同的项。
// 先遍历第一个集合,找出所有唯一的元素,然后再遍历第二个集合,
// 返回第二个集合中所有未出现在前面所得元素集合中的元素。
Console.WriteLine("--------------与非操作----------");
var query21 = (from a in pers2 select new { Age = a.age, Name = a.name })
.Except(from p in ani2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query21)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
//11.210 分区
//扩展方法 Take与Skip等分区操作可以用于分页,例如显示5*5个人
//一页显示的条数
int pageSize = 2;
//页数计算
int numberPages = (int)Math.Ceiling(GetMyList().Count() / (double)pageSize);
for (int page = 0; page < numberPages; page++)
{
Console.WriteLine("-------------------第{0}页-------------------------------", page);
var persons = ( from r in GetMyList() select r.name ).Skip( page * pageSize ).Take( pageSize ) ;
foreach( var a in persons )
{
Console.WriteLine( a ) ;
}
}
//可以看出skip是指忽略多少条,Take是指从取到的记录中取几条
//11,2,11合并操作
//Count用来计算项目数,下面我们选中拥有车超过3辆的人
var query22 = from person in GetMyList() where person.list.Count() >= 2 select new { Name = person.name , Age = person.age , Count = person.list.Count() } ;
Console.WriteLine( "-----------------------选出拥有车俩3俩以上的人------------" ) ;
foreach( var a in query22 )
{
Console.WriteLine( a.Name + " " + a.Age + " " + a.Count ) ;
}
//Sum汇总数字的合
//下面,我们用Sum求出所有人年纪的总合(按人名先分组)
Console.WriteLine( "-------------------------所有人年纪的总合------------------" ) ;
var query23 = from ppp in GetMyList()
group ppp by ppp.name into g
select new
{
Name = g.Key,
AgeSum = (from p in pers select p.age).Sum(),
Count = g.Count()
};
foreach (var a in query23)
{
Console.WriteLine(a.Name + " " + a.AgeSum + " " + a.Count );
}
//11.2.12转换
//之前我们用到的查询,都是在foreach时才会真正的执行,下面我们的方式是强制立即执行,将结果放数集合数组等容器中
List list = (from p in GetMyList() select p).ToList();
Console.WriteLine("立即执行查询-----------------------");
foreach (var a in list)
{
Console.WriteLine(a.age + a.name ) ;
foreach( var p in a.list )
{
Console.WriteLine( p.name ) ;
}
}
//接着,我们做一个字典,车对人(一对多)
ILookup per111 = (from per in GetMyList()
from c in per.list
select new
{
Car = c.name,
Person = per
}).ToLookup(p => p.Car, p => p.Person);
Console.WriteLine( per111.Count ) ;
if ( per111.Contains("奔驰") )
{
foreach( var p in per111["奔驰"] )
{
Console.WriteLine( "有这个车的人:{0}" , p.name ) ;
}
}
//如果要在非泛型版的集合上使用,可以用Cast方法强制得到类型
ArrayList arr = new ArrayList( GetMyList() as ICollection ) ;
var qqq = from a in arr.Cast() where a.name == "aladdin" select a ;
//11.2.13生成操作符
// Range() Empty() Repear()不是扩展方法,而是返回序列的正常静态方法
// 在LINQ to Objects中,这些方法可以用于Enumearable类
// 有时需要填充一个范围的数字,这时需要用到Range方法,第一个参数做为起始值,第二个是指填充的项目数
var values = Enumerable.Range( 1 ,20 ).Select( n => n*3 ) ;
foreach( var a in values )
{
Console.Write( a + " " ) ;
}
//结果1 2 3 4 .....20
//比如某个方法,参数是一个集合,我们传一个空进去,就可以用Empty
var em = Enumerable.Empty() ;
var pep = Enumerable.Repeat( "fuck " , 10 ) ;
foreach( var a in pep )
{
Console.WriteLine( a ) ;
}
//Repeat用于把特定元素按指定的重复次数爹代
Console.ReadLine();
}
public static void PrintMyInfo(IEnumerable en)
{
foreach (Person per in en)
{
Console.WriteLine("姓名:{0} 年龄:{1}", per.name, per.age);
}
}
public static IEnumerable GetMyAnimalList()
{
List lists = new List();
Animal p1 = new Animal("aladdin", 21);
Animal p2 = new Animal("apple", 22);
Animal p3 = new Animal("angel", 30);
Animal p4 = new Animal("jacky", 22);
lists.Add(p1);
lists.Add(p2);
lists.Add(p3);
lists.Add(p4);
return lists;
}
public static IEnumerable GetMyList()
{
List lists = new List();
Person p1 = new Person("aladdin", 21);
Person p2 = new Person("apple", 22);
Person p3 = new Person("angel", 30);
Person p4 = new Person("jacky", 20);
Person p5 = new Person("zhao", 11);
Person p6 = new Person("fuck", 33);
Person p7 = new Person("emep", 25);
Person p8 = new Person("xiaoming", 88);
Person p9 = new Person("along", 88);
Person p10 = new Person("dafei", 99);
Person p11 = new Person("bige", 99);
Person p12 = new Person("feitianlong", 77);
Person p13 = new Person("dalianmao", 77);
Person p14 = new Person("guixianren", 21);
Person p15 = new Person("yuebuqun", 21);
p1.list.Add(new Cars("奔驰"));
p1.list.Add(new Cars("宝马"));
p1.list.Add(new Cars("拖拉机"));
p2.list.Add(new Cars("自行车"));
p2.list.Add(new Cars("摩托"));
p3.list.Add(new Cars("奔驰"));
p3.list.Add(new Cars("陆虎"));
p4.list.Add(new Cars("捷达"));
p4.list.Add(new Cars("哈飞"));
p5.list.Add(new Cars("奔驰"));
p5.list.Add(new Cars("宝时捷"));
p6.list.Add(new Cars("奔驰"));
p6.list.Add(new Cars("霸道"));
p7.list.Add(new Cars("昌河"));
p7.list.Add(new Cars("长安之星"));
lists.Add(p1);
lists.Add(p2);
lists.Add(p3);
lists.Add(p4);
lists.Add(p5);
lists.Add(p6);
lists.Add(p7);
lists.Add(p8);
lists.Add(p9);
lists.Add(p10);
lists.Add(p11);
lists.Add(p12);
lists.Add(p13);
lists.Add(p14);
lists.Add(p15);
return lists;
}
}
class Person
{
public string name;
public int age;
public List list = new List();
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}
class Cars
{
public string name;
public Cars(string name)
{
this.name = name;
}
}
class Animal
{
public string name;
public int age;
public Animal(string name, int age)
{
this.name = name;
this.age = age;
}
}
}
[/codes] =>>
using System;
using System.Collections.Generic;
using System.Collections ;
using System.Linq;
using System.Text;
namespace LINQ技术
{
class LINQ查询操作符
{
public static void Main()
{
//首先,我们先列出Linq一些常用的操作符
// Where 与 OfType
// OfType
// 11.2.1过滤
IEnumerable
var query1 = from p in list1 where p.age >= 20 select p;
Console.WriteLine("-----------------过滤:大于等于20岁的人员-------------");
PrintMyInfo(query1);
//下面我们写一个对象查询的版本
Console.WriteLine("-----------------过滤:大于等于30岁的人员(对象版本)-------------");
list1 = list1.Where
PrintMyInfo(list1);
// 11.2.2 用索引来过滤
//这是一个无法使用LINQ语句来实现的功能,他是Where方法的重载
//在这个方法中,可以传入第二个参数---索引
//可以是过滤器返回个数的计数器,可以在表达式中使用这个索引,执行基于索引的计算。
//public delegate TResult Func
IEnumerable
list2 = list2.Where
Console.WriteLine("-------------基于索引过滤:姓名以A开头,只要2名,多了不要-------------");
PrintMyInfo(list2);
// 11.2.3 类型过滤
//假定一个数组包含有整型,与字符型元素,而我们只想过滤出字符型元素。呵呵,这么怪的东西,一般是没有啦
object[] objs = new object[] { 232, 23, 3232, "aladdin", 332, 32323, "fuck" };
var query2 = objs.OfType
Console.WriteLine("-----------类型过滤,只要string型的元素---------");
foreach (string s in query2)
{
Console.WriteLine(s);
}
// 11.2.4 符合的form子句
// 如果需要根据对象的一个成员过滤,而该成员本身又是一个系列,就要用到符合子句
// 下面,我们要先出,所年龄在25以上,并且拥有一输开奔驰的牛B人物(一个人可以有多个车)。。我连个蛋蛋也没有,乃球
IEnumerable
Console.WriteLine("-----------复合子句,所年龄在25以上,并且拥有一输开奔驰的牛B人物---------");
var quer3 = from p in list3 from c in p.list where c.name.Equals("奔驰") where p.age >= 25 select (p);
PrintMyInfo(quer3);
//下面我们来分析一下select投影方法
//public static IEnumerable
//Select
//IEnumerable
//2个参数 :this IEnumerable
// Func
// 委托的声明: public delegate TResult Func
IEnumerable
var query4 = list4.Select(p => p.age);
//Select第一个参数是隐式的,所以我们不用关心,只要明白它是扩展哪个类型就可以了
//第二个参数通过源类型,返回一个投影类型,可以是源类型的一个字段,也可以将源类型直接返回,也就是我们直接写 select p
//以上示例,我们是将源类型中的age返回,它是int 型。下面我们跌代,就不可以用Person来跌代了。
Console.WriteLine("-----------按年纪投影---------");
foreach (int p in query4)
{
Console.WriteLine(p);
}
//在select与where这两个方法上,可能会存在一点误解,我开始认为select可以做与where一样的事情,下面我们证实一下
var query5 = list4.Select(p =>
{
if (p.age >= 25)
{
return new Person(p.name, p.age);
}
else
{
return new Person("node", 1);
}
});
//以上代码,我们想用select来过滤超过25岁的人,但是,无法将不需要的部分不要,所以,还是没办法做与where一样的功能
//而where方法,返回的是bool,可以筛选不合格的条件的。
Console.WriteLine("-----------select模拟 where ---------");
foreach (Person p in query5)
{
Console.WriteLine(p.name);
}
//看完了select我们接着看SelectMany方法,其实复合查询中,就是用到了这个方法。
//public static IEnumerable
// this IEnumerable
// Func
// Func
//)
//返回IEnumerable
//3个参数,第一个是隐式的,也就是指明他扩展的是哪种类型的this IEnumerable
//第二个参数,是一个委托 Func
//下面我们看这个委托的声明:public delegate TResult Func
//这里与select方法有一点不同,select用委托做参数时保留了TResult类型,而这里我们指定成了IEnumerable
//第三个参数,同样也是一个委托 Func
//public delegate TResult Func
IEnumerable
//以下示例是SelectMany方法的第一种重载,只是将一个序列的子集序列查出来
var query6 = list5.SelectMany(par => par.list).Where(p => p.name.Equals("奔驰"));
Console.WriteLine("查询序列的序列-------------------");
foreach (Cars car in query6)
{
Console.WriteLine(car.name);
}
//我们用对象方法的方式来查询一次所有25岁以上的拥有奔驰车的牛B人物
var query7 = list5.SelectMany(cars => cars.list, (per, car) => new { Person = per, Cars = car }).Where(p => p.Person.age >= 25 && p.Cars.name.Equals("奔驰")).Select(par => par.Person.name);
Console.WriteLine("对象方式复合查询-------------------");
foreach (var a in query7)
{
Console.WriteLine(a);
}
// 11.2.5 排序
// 下面我们写一个小例,把人按照年纪排一次序
var query8 = list5.Select(p => p).OrderBy(p => p.age).ThenBy(p => p.name);
var query9 = list5.Select(p => p).OrderByDescending(p => p.age).Take(2);
Console.WriteLine("------------升序所有人--------------");
PrintMyInfo(query8);
Console.WriteLine("降序所有人--------------------");
PrintMyInfo(query9);
// Order 与 OrderByDescending方法都是返回IOrderedEnumerable
//public static IOrderedEnumerable
// this IEnumerable
// Func
//)
// 11.2.6 分组
//下面我们先用linq 语句实现分组查询,我们把人的年纪分组,我们只接受元素大于2个的组,每一组我们个数排,如果个数相同,我们按年纪排。
var query10 = from per in list5
group per by per.age into g
orderby g.Count(), g.Key
where g.Count() >= 2
select new { Age = g.Key, Count = g.Count() };
Console.WriteLine("--------分组查询-----------");
foreach (var a in query10)
{
Console.WriteLine(a.Age + " " + a.Count);
}
//方法方式实现上面功能
var query11 = list5.GroupBy(per => per.age)
.OrderBy(p => p.Count()).ThenBy(p => p.Key)
.Where(p => p.Count() >= 2)
.Select(p => new { Age = p.Key, Count = p.Count() });
Console.WriteLine("--------分组查询,方法方式-----------");
foreach (var a in query11)
{
Console.WriteLine(a.Age + " " + a.Count);
}
// 11.2.7 对嵌套的对象分组
//如上所示,我们将年纪分组,如果想要把组内人员的名字一并返回,势必将名字会当成一个序列,此时,它是一对多的关系
Console.WriteLine("---------嵌套对象分组-------------");
var query12 = list5.GroupBy(per => per.age)
.OrderBy(p => p.Count()).ThenBy(p => p.Key)
.Where(p => p.Count() >= 2)
.Select(p => new
{
Age = p.Key,
Count = p.Count(),
Persons = from per in p orderby per.name select per
});
foreach (var a in query12)
{
Console.WriteLine(a.Age + " " + a.Count);
foreach (var b in a.Persons)
{
Console.WriteLine(b.name);
}
}
// 11.2.8 连接
//搞不个恰当的例子吧,我们现在扩展一种类,来描述动物,同样具有名字与年纪,我们用连接,查询与动物相同年纪的人
var query13 = GetMyAnimalList().Select(animal => animal);
var query14 = GetMyList().Select(person => person);
var query15 = from per in query14
join animal in query13 on per.age equals animal.age
select new
{
DogName = animal.name,
DogAge = animal.age,
PersonName = per.name,
PersonAge = per.age
};
foreach (var v in query15)
{
Console.WriteLine("人名:{0} , 年纪{1}------动物名:{2} ,年纪{3}", v.PersonName, v.PersonAge, v.DogName, v.DogAge);
}
// 11.2.9 设置方法
//Concat(连接)
//说明:连接不同的集合,不会自动过滤相同项;延迟。
IEnumerable
IEnumerable
int i = 0;
var query16 = (from a in ani select a.name).Concat(from p in pers select p.name);
Console.WriteLine("--------------连接操作----------");
foreach (var str in query16)
{
++i;
Console.WriteLine(str);
}
Console.WriteLine("个数:" + i);
//可以看出,我们将所有人与动物的名字做了一个连接操作,全部显示了出,不过并没有自动过滤重复项目
//以上示例,只是连接了一个字段,下面我们复合型式连接
Console.WriteLine("--------------复合连接操作----------");
var query17 = (from a in ani select new { Name = a.name, Age = a.age })
.Concat(from p in pers select new { Name = p.name, Age = p.age });
i = 0;
foreach (var str in query17)
{
++i;
Console.WriteLine(str.Name + " " + str.Age);
}
Console.WriteLine("个数:" + i);
//Union(合并)
//说明:连接不同的集合,自动过滤相同项;延迟。即是将两个集合进行合并操作,过滤相同的项。
var query18 = (from a in ani select a.name).Union(from p in pers select p.name);
Console.WriteLine("--------------合并操作----------");
i = 0;
foreach (var str in query18)
{
Console.WriteLine(str);
++i;
}
Console.WriteLine("个数:" + i);
//可以看出,我们将所有人与动物的名字做了一个连接操作,全部显示了出,不过并没有自动过滤重复项目
//以上示例,只是连接了一个字段,下面我们复合型式连接
IEnumerable
IEnumerable
Console.WriteLine("--------------复合合并操作----------");
var query19 = (from a in ani2 select new { Age = a.age, Name = a.name })
.Union(from p in pers2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query19)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
//这时有一点疑问,并集比较时,没有按匿名对象,而依然是在用 name,不知道为什么
// Intersect(相交)
//说明:取相交项;延迟。即是获取不同集合的相同项(交集)。即先遍历第一个集合,找出所有唯一的元素,
//然后遍历第二个集合,并将每个元素与前面找出的元素作对比,返回所有在两个集合内都出现的元素。
Console.WriteLine("--------------相交操作----------");
var query20 = (from a in ani2 select new { Age = a.age, Name = a.name })
.Intersect(from p in pers2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query20)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
// Except(与非)
//说明:排除相交项;延迟。即是从某集合中删除与另一个集合中相同的项。
// 先遍历第一个集合,找出所有唯一的元素,然后再遍历第二个集合,
// 返回第二个集合中所有未出现在前面所得元素集合中的元素。
Console.WriteLine("--------------与非操作----------");
var query21 = (from a in pers2 select new { Age = a.age, Name = a.name })
.Except(from p in ani2 select new { Age = p.age, Name = p.name });
i = 0;
foreach (var str in query21)
{
++i;
Console.WriteLine(str.Age + " " + str.Name);
}
Console.WriteLine("个数:" + i);
//11.210 分区
//扩展方法 Take与Skip等分区操作可以用于分页,例如显示5*5个人
//一页显示的条数
int pageSize = 2;
//页数计算
int numberPages = (int)Math.Ceiling(GetMyList().Count() / (double)pageSize);
for (int page = 0; page < numberPages; page++)
{
Console.WriteLine("-------------------第{0}页-------------------------------", page);
var persons = ( from r in GetMyList() select r.name ).Skip( page * pageSize ).Take( pageSize ) ;
foreach( var a in persons )
{
Console.WriteLine( a ) ;
}
}
//可以看出skip是指忽略多少条,Take是指从取到的记录中取几条
//11,2,11合并操作
//Count用来计算项目数,下面我们选中拥有车超过3辆的人
var query22 = from person in GetMyList() where person.list.Count() >= 2 select new { Name = person.name , Age = person.age , Count = person.list.Count() } ;
Console.WriteLine( "-----------------------选出拥有车俩3俩以上的人------------" ) ;
foreach( var a in query22 )
{
Console.WriteLine( a.Name + " " + a.Age + " " + a.Count ) ;
}
//Sum汇总数字的合
//下面,我们用Sum求出所有人年纪的总合(按人名先分组)
Console.WriteLine( "-------------------------所有人年纪的总合------------------" ) ;
var query23 = from ppp in GetMyList()
group ppp by ppp.name into g
select new
{
Name = g.Key,
AgeSum = (from p in pers select p.age).Sum(),
Count = g.Count()
};
foreach (var a in query23)
{
Console.WriteLine(a.Name + " " + a.AgeSum + " " + a.Count );
}
//11.2.12转换
//之前我们用到的查询,都是在foreach时才会真正的执行,下面我们的方式是强制立即执行,将结果放数集合数组等容器中
List
Console.WriteLine("立即执行查询-----------------------");
foreach (var a in list)
{
Console.WriteLine(a.age + a.name ) ;
foreach( var p in a.list )
{
Console.WriteLine( p.name ) ;
}
}
//接着,我们做一个字典,车对人(一对多)
ILookup
from c in per.list
select new
{
Car = c.name,
Person = per
}).ToLookup(p => p.Car, p => p.Person);
Console.WriteLine( per111.Count ) ;
if ( per111.Contains("奔驰") )
{
foreach( var p in per111["奔驰"] )
{
Console.WriteLine( "有这个车的人:{0}" , p.name ) ;
}
}
//如果要在非泛型版的集合上使用,可以用Cast方法强制得到类型
ArrayList arr = new ArrayList( GetMyList() as ICollection ) ;
var qqq = from a in arr.Cast
//11.2.13生成操作符
// Range() Empty() Repear()不是扩展方法,而是返回序列的正常静态方法
// 在LINQ to Objects中,这些方法可以用于Enumearable类
// 有时需要填充一个范围的数字,这时需要用到Range方法,第一个参数做为起始值,第二个是指填充的项目数
var values = Enumerable.Range( 1 ,20 ).Select( n => n*3 ) ;
foreach( var a in values )
{
Console.Write( a + " " ) ;
}
//结果1 2 3 4 .....20
//比如某个方法,参数是一个集合,我们传一个空进去,就可以用Empty
var em = Enumerable.Empty
var pep = Enumerable.Repeat( "fuck " , 10 ) ;
foreach( var a in pep )
{
Console.WriteLine( a ) ;
}
//Repeat用于把特定元素按指定的重复次数爹代
Console.ReadLine();
}
public static void PrintMyInfo(IEnumerable
{
foreach (Person per in en)
{
Console.WriteLine("姓名:{0} 年龄:{1}", per.name, per.age);
}
}
public static IEnumerable
{
List
Animal p1 = new Animal("aladdin", 21);
Animal p2 = new Animal("apple", 22);
Animal p3 = new Animal("angel", 30);
Animal p4 = new Animal("jacky", 22);
lists.Add(p1);
lists.Add(p2);
lists.Add(p3);
lists.Add(p4);
return lists;
}
public static IEnumerable
{
List
Person p1 = new Person("aladdin", 21);
Person p2 = new Person("apple", 22);
Person p3 = new Person("angel", 30);
Person p4 = new Person("jacky", 20);
Person p5 = new Person("zhao", 11);
Person p6 = new Person("fuck", 33);
Person p7 = new Person("emep", 25);
Person p8 = new Person("xiaoming", 88);
Person p9 = new Person("along", 88);
Person p10 = new Person("dafei", 99);
Person p11 = new Person("bige", 99);
Person p12 = new Person("feitianlong", 77);
Person p13 = new Person("dalianmao", 77);
Person p14 = new Person("guixianren", 21);
Person p15 = new Person("yuebuqun", 21);
p1.list.Add(new Cars("奔驰"));
p1.list.Add(new Cars("宝马"));
p1.list.Add(new Cars("拖拉机"));
p2.list.Add(new Cars("自行车"));
p2.list.Add(new Cars("摩托"));
p3.list.Add(new Cars("奔驰"));
p3.list.Add(new Cars("陆虎"));
p4.list.Add(new Cars("捷达"));
p4.list.Add(new Cars("哈飞"));
p5.list.Add(new Cars("奔驰"));
p5.list.Add(new Cars("宝时捷"));
p6.list.Add(new Cars("奔驰"));
p6.list.Add(new Cars("霸道"));
p7.list.Add(new Cars("昌河"));
p7.list.Add(new Cars("长安之星"));
lists.Add(p1);
lists.Add(p2);
lists.Add(p3);
lists.Add(p4);
lists.Add(p5);
lists.Add(p6);
lists.Add(p7);
lists.Add(p8);
lists.Add(p9);
lists.Add(p10);
lists.Add(p11);
lists.Add(p12);
lists.Add(p13);
lists.Add(p14);
lists.Add(p15);
return lists;
}
}
class Person
{
public string name;
public int age;
public List
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}
class Cars
{
public string name;
public Cars(string name)
{
this.name = name;
}
}
class Animal
{
public string name;
public int age;
public Animal(string name, int age)
{
this.name = name;
this.age = age;
}
}
}
[/codes]
4月3
After a query has been executed all successive queries will use the in-memory LINQ operators. Iterating over the query variable by using a foreach or For Each statement or by calling one of the LINQ conversion operators will cause immediate execution. These conversion operators include the following: ToList, ToArray, ToLookup, and ToDictionary.
·Select - Select选择;延迟
·Where - Where查询;延迟
·OrderBy - 按指定表达式对集合正序排序;延迟
·OrderByDescending - 按指定表达式对集合倒序排序;延迟
·GroupBy - 分组;延迟
·Join - Join查询;延迟
·GroupJoin - 分组Join查询;延迟
·Distinct - 过滤集合中的相同项;延迟
·Union - 连接不同集合,自动过滤相同项;延迟
·Concat - 连接不同集合,不会自动过滤相同项;延迟
·Intersect - 获取不同集合的相同项(交集);延迟
·Except - 从某集合中删除其与另一个集合中相同的项;延迟
·Skip - 跳过集合的前n个元素;延迟
·Take - 获取集合的前n个元素;延迟
·SkipWhile - 直到某一条件成立就停止跳过;延迟
·TakeWhile - 直到某一条件成立就停止获取;延迟
·Single - 根据表达式返回集合中的某一元素;不延迟
·SingleOrDefault - 根据表达式返回集合中的某一元素(如果没有则返回默认值);不延迟
·Reverse - 对集合反向排序;延迟
·SelectMany - Select选择(一对多);延迟
·Select - Select选择;延迟
·Where - Where查询;延迟
·OrderBy - 按指定表达式对集合正序排序;延迟
·OrderByDescending - 按指定表达式对集合倒序排序;延迟
·GroupBy - 分组;延迟
·Join - Join查询;延迟
·GroupJoin - 分组Join查询;延迟
·Distinct - 过滤集合中的相同项;延迟
·Union - 连接不同集合,自动过滤相同项;延迟
·Concat - 连接不同集合,不会自动过滤相同项;延迟
·Intersect - 获取不同集合的相同项(交集);延迟
·Except - 从某集合中删除其与另一个集合中相同的项;延迟
·Skip - 跳过集合的前n个元素;延迟
·Take - 获取集合的前n个元素;延迟
·SkipWhile - 直到某一条件成立就停止跳过;延迟
·TakeWhile - 直到某一条件成立就停止获取;延迟
·Single - 根据表达式返回集合中的某一元素;不延迟
·SingleOrDefault - 根据表达式返回集合中的某一元素(如果没有则返回默认值);不延迟
·Reverse - 对集合反向排序;延迟
·SelectMany - Select选择(一对多);延迟
10月28
1.简单形式:
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select g;
[/codes]
语句描述:Linq使用Group By按CategoryID划分产品。
说明:from p in db.Products 表示从表中将产品对象取出来。group p by p.CategoryID into g表示对p按CategoryID字段归类。其结果命名为g,一旦重新命名,p的作用域就结束了,所以,最后select时,只能select g。
2.最大值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
MaxPrice = g.Max(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Max查找每个CategoryID的最高单价。
说明:先按CategoryID归类,判断各个分类产品中单价最大的Products。取出CategoryID值,并把UnitPrice值赋给MaxPrice。
3.最小值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
MinPrice = g.Min(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Min查找每个CategoryID的最低单价。
说明:先按CategoryID归类,判断各个分类产品中单价最小的Products。取出CategoryID值,并把UnitPrice值赋给MinPrice。
4.平均值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
AveragePrice = g.Average(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Average得到每个CategoryID的平均单价。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品中单价的平均值。
5.求和
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
TotalPrice = g.Sum(p => p.UnitPrice)
};
[/codes]
6.计数
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
NumProducts = g.Count()
};
[/codes]
语句描述:Linq使用Group By和Count得到每个CategoryID中产品的数量。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品的数量。
7.带条件计数
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
NumProducts = g.Count(p => p.Discontinued)
};
[/codes]
语句描述:Linq使用Group By和Count得到每个CategoryID中断货产品的数量。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品的断货数量。 Count函数里,使用了Lambda表达式,Lambda表达式中的p,代表这个组里的一个元素或对象,即某一个产品。
8.Where限制
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
where g.Count() >= 10
select new {
g.Key,
ProductCount = g.Count()
};
[/codes]
语句描述:根据产品的―ID分组,查询产品数量大于10的ID和产品数量。这个示例在Group By子句后使用Where子句查找所有至少有10种产品的类别。
说明:在翻译成SQL语句时,在最外层嵌套了Where条件。
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select g;
[/codes]
语句描述:Linq使用Group By按CategoryID划分产品。
说明:from p in db.Products 表示从表中将产品对象取出来。group p by p.CategoryID into g表示对p按CategoryID字段归类。其结果命名为g,一旦重新命名,p的作用域就结束了,所以,最后select时,只能select g。
2.最大值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
MaxPrice = g.Max(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Max查找每个CategoryID的最高单价。
说明:先按CategoryID归类,判断各个分类产品中单价最大的Products。取出CategoryID值,并把UnitPrice值赋给MaxPrice。
3.最小值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
MinPrice = g.Min(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Min查找每个CategoryID的最低单价。
说明:先按CategoryID归类,判断各个分类产品中单价最小的Products。取出CategoryID值,并把UnitPrice值赋给MinPrice。
4.平均值
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
AveragePrice = g.Average(p => p.UnitPrice)
};
[/codes]
语句描述:Linq使用Group By和Average得到每个CategoryID的平均单价。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品中单价的平均值。
5.求和
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
TotalPrice = g.Sum(p => p.UnitPrice)
};
[/codes]
6.计数
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
NumProducts = g.Count()
};
[/codes]
语句描述:Linq使用Group By和Count得到每个CategoryID中产品的数量。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品的数量。
7.带条件计数
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
select new {
g.Key,
NumProducts = g.Count(p => p.Discontinued)
};
[/codes]
语句描述:Linq使用Group By和Count得到每个CategoryID中断货产品的数量。
说明:先按CategoryID归类,取出CategoryID值和各个分类产品的断货数量。 Count函数里,使用了Lambda表达式,Lambda表达式中的p,代表这个组里的一个元素或对象,即某一个产品。
8.Where限制
[codes=c#]
var q =
from p in db.Products
group p by p.CategoryID into g
where g.Count() >= 10
select new {
g.Key,
ProductCount = g.Count()
};
[/codes]
语句描述:根据产品的―ID分组,查询产品数量大于10的ID和产品数量。这个示例在Group By子句后使用Where子句查找所有至少有10种产品的类别。
说明:在翻译成SQL语句时,在最外层嵌套了Where条件。
10月16
[codes=c#]
SQL:
Select C.sName as CustomerName, S.sName as Salesperson,
Sum(O.nQty) as Qty, Sum(O.mAmount) as Amount
From tOrders O
Inner Join tCustomer C On C.CustomerID = O.CustomerID
Inner Join tSalesperson S On S.SalespersonID = O.SalespersonID
Group By C.sName, S.sName
LINQ:
var query = from order in db.Orders
group order by new { Customer = order.Customer,
SalesPerson = order.SalesPerson }
into grp
select new
{
Customer = grp.Key.Customer.Name,
SalesPerson = grp.Key.SalesPerson.Name,
Quantity = grp.Sum(o => o.Quantity),
Amount = grp.Sum(o => o.Amount)
};
[/codes]
SQL:
Select C.sName as CustomerName, S.sName as Salesperson,
Sum(O.nQty) as Qty, Sum(O.mAmount) as Amount
From tOrders O
Inner Join tCustomer C On C.CustomerID = O.CustomerID
Inner Join tSalesperson S On S.SalespersonID = O.SalespersonID
Group By C.sName, S.sName
LINQ:
var query = from order in db.Orders
group order by new { Customer = order.Customer,
SalesPerson = order.SalesPerson }
into grp
select new
{
Customer = grp.Key.Customer.Name,
SalesPerson = grp.Key.SalesPerson.Name,
Quantity = grp.Sum(o => o.Quantity),
Amount = grp.Sum(o => o.Amount)
};
[/codes]
8月13
6月12