在C#中利用Linq进行一些集合的操作是十分方便的,传统的一些编程方式自然也能相同的功能,不过使用Linq更加的优雅。
C#的一些高级语言特性确实令人着迷。
我这边就直接通过几个例子来展现一下Linq的强大,就不说逐字逐句的扣语法了。
Linq之前:
在写Linq之前有几个C#新的知识点必须掌握才能学习它。
1.匿名对象:
学过Java的同学知道匿名对象的强大之处,一个接口可以直接通过new关键字来产生一个对象,在new的过程中可以指定需要override的方法,填加新的字段。
不过在C#中,Java的匿名对象被分为了两个知识点,一个是delegate,另一个就是现在要说的匿名对象,在C#中的匿名对象只能添加字段,而不能添加方法。
例子如下:
var psn = new { name = "小明" };
Console.WriteLine(psn.name);
因为只能添加字段,所以平时大家也不常用,可以说这个东西是专门为Linq准备的。
2.lambda表达式:
上面说了delegate,而delegate的创建方式有两种,一种是直接把类中的函数赋值进去,另一种是匿名函数,也就这边的lambda表达式了。
关于delegate实际上是一种将方法(函数)作为对象存储到变量中的一种技术,如果对这个不是很了解,建议写几个程序练习一下。
这边给出lambda和普通函数的对比:
static void Main_Delegate(string[] args)
{
Action method_lambda = () =>
{
Console.WriteLine("Hello");
};
Action method_normal = PrintHello;
method_lambda();
method_normal();
}
static void PrintHello()
{
Console.WriteLine("Hello");
}
正式Linq的练习:
首先在写之前,需要知道Linq其实就是对集合提供类似于sql一般的操作。
我们准备好今天需要查询的数据:
class Person
{
public string name;
public int age;
public override string ToString()
{
return "name: " + name + ", age: " + age;
}
}
class Course
{
public string personName;
public string name;
public int score;
public override string ToString()
{
return "name: " + name + ", score: " + score + ", personName: " + personName;
}
}
List<Person> list = new List<Person>();
list.Add(new Person(){ name = "小明", age = 19});
list.Add(new Person(){ name = "小红", age = 17});
list.Add(new Person(){ name = "小强", age = 20});
List<Course> list2 = new List<Course>();
list2.Add(new Course(){ personName = "小明", name = "数学", score = 90});
list2.Add(new Course(){ personName = "小明", name = "英语", score = 56});
list2.Add(new Course(){ personName = "小红", name = "数学", score = 60});
list2.Add(new Course(){ personName = "小红", name = "英语", score = 100});
一些人和他们本次考试的成绩。
1.马上来做第一个查询,查询所有年龄大于18岁的人:
from p in list
where p.age > 18
select p
这就是一个最简单的查询了,需要记住的是每个查询都是以from ... in ...开头,select或group结尾。
Linq有两种表达形式,一种就是以上类似于sql的表达式,另一种是使用IEnumerable的扩展方法:
list.Where(p=>p.age>18);
效果是一样的,都属于Linq。这边再提一个方法,List的FindAll方法:
list.FindAll(p => p.age > 18);
通过以上的方式,返回的结果和上面两种方式是一模一样的,不过FindAll方法属于List,而上面两种Linq是基于IEnumerable接口的,所以我们知道了,Linq的集合接口的基础就是IEnumerable,只要实现了该接口的集合就能做Linq操作。
第一个说的可能比较多,下面就快了。
2.多集合查询,查询所有及格的课程对应的人:
from p in list
from c in list2
where c.personName == p.name && c.score >= 60
select new{c, p}
list.SelectMany(c=>list2, (person, course) => new {person, course} )
.Where(x=>x.course.personName==x.person.name & x.course.score>=60)
这边SelectMany将list和list2映射到一个新的匿名集合,这边我取名为x,而两个新的集合名分别为person和course。
3.使用Join代替多集合查询:
from p in list
join c in list2 on p.name equals c.personName
where c.score >= 60
select new { c, p }
list.Join(list2, p=>p.name, c=>c.personName, (p, c) => new { c, p })
.Where(x=>x.c.score >= 60)
跟上面的多集合查询效果是一样的,只不过就是把相等条件提取出来了而已。
4.使用into关键字,查询选课数量:
from p in list
join c in list2 on p.name equals c.personName
into groups
select new { p.name, count = groups.Count() }
list.GroupJoin(list2, p=>p.name, c=>c.personName, (p, cs)=>new{p.name, count=cs.Count()})
通过from和join之后产生了一个大集合,而into将p为同一个的查询记录放到同一个集合groups中。
也就是将同一个人的课程放到groups集合中,调用groups.Count()自然是课程的数量
5.查询课程选修的人数:
from c in list2
group c by c.name into cs
select new {name=cs.Key, count=cs.Count()}
list2.GroupBy(c=>c.name).Select((cs)=>new{name=cs.Key, count=cs.Count()})
使用group by关键字将课程名相同的放到一个集合中,原理跟上面查询是一样。
以上是几个基本的练习,感觉掌握了这些,面对大部分需求应该是没有问题的了,以后学到了新的还会继续补充。
6.从0遍历到99:
from i in Enumerable.Range(0, 99) select i
7.99重复10遍:
from i in Enumerable.Repeat(99, 10) select i