linq实现为一系列扩展方法,用于集合、数组、查询结果和其他执行了IEnumberabe接口的对象。
where<>方法和大多数其他方法都是扩展方法,这些方法在顶部注释掉了指令using.system.Linq,表示它们是linq的扩展,但列表中where<>、union<>、take<>和大多数其他方法都没有这个指令。
from..where..select查询表达式由c#编译器转换这些方法的一系列调用。使用linq方法时,就直接调用这些方法。
(蓝字部分不是很理解)
查询语法和方法语法
大多数使用方法语法的linq方法都要求传送一个方法或函数,来计算查询表达式。方法/函数参数以委托的形式传送,它一般是一个匿名方法。
使用拉姆达表达式是编写匿名方法的简洁方式。
参数列 => 语句或语句块
拉姆达表达式是定义函数的缩写方式,对于示例n=>n<1000,拉姆达表达式定义了一个函数,其参数是n,如果n<1000,该函数就返回true,如果n大于1000,函数就返回false.函数是没有名称的匿名方法。仅在把拉姆达表达式传给底层的linq方法时调用。
查询语法:from s in strs where s startwith(“a”) select s ,where子句
方法语法:str.where(s=>s.startwith(“a”)),是where方法的调用,而不是查询表达式。
排序查询结果:
orderby子句排序:
from s in strs where s startwith(“a”) orderby s select s
orderby子句默认为升序,但可以添加descending关键字,指定降序。(Z到A)
from s in strs where s startwith(“a”) orderby descending s select s
可以按照任意表达式进行排序,而无需重新编写查询。例如按照字符串的最后一个字母排序:
from s in strs where s startwith(“a”) orderby s.substring(s.length-1) select s
用方法语法排序
//升序
var strss = strs.OrderBy(s => s).Where(s => s.StartsWith("a"));
//逆序
var strssDescend = strs.OrderByDescending(s=>s).Where(s=>s.StartsWith("a"));
//以最后一个字母逆序
var strssLast = strs.OrderBy(s => s.Substring(s.Length - 1)).Where(s => s.StartsWith("a"));
查询大型数据集
合计运算符
count():结果的个数
min():结果的最小值
max():结果的最大值
avcrage():数字结果的平均值
sum():所有数字结果的综合
注意的地方:
console.wirteLine(queryResults.Sum(n=>(long)n))
因为总和太大,不能放在sum()方法的无参数重载版本返回的标准32位int中。拉姆达表达式允许把sum()方法的结果转换为64位长整数。
count()返回32位int,linq还提供了一个LongCount()方法,它在64位整数中返回查询结果的个数。但有一个特殊情况,如果需要数字的64位版本,所有其他运算符都需要一个拉姆达表达式或转换方法调用。
查询复杂的对象
public class Person
{
public int age { get; set; }
public string name { get; set; }
public int sex { get; set; }
//重写了ToString(),默认的ToString()会输出类型的名称
public override string ToString()
{
return "age:" + age +" "+ "name:" + name+" " + "sex:" + sex;
}
}
List<Person> personList = new List<Person> {
new Person{age = 1,name="a",sex=1},
new Person{age = 2,name="b",sex=2},
new Person{age = 3,name="c",sex=1},
new Person{age = 4,name="a",sex=1}
};
personList为一个强类型化的集合,其类型是Person,这样就不用编写构造方法,再调用构造方法创建每个列表成员了。
投射:在查询中创建新对象
投射是在Linq查询中从其他数据类型中创建新数据类型的技术术语,select关键字是投射运算符。
从数据对象中选取某个字段而不是整个对象:
例子:只检索sex字段
from p in personList where p.name == “a” select p.sex
创建新对象
使用c#3.0匿名类型创建语法,创建一个未命名的对象类型,带有name,age,sex属性。
var ppList = from p in personList where p.name == "a" select new { p.name, p.age, p.sex };
投射:方法语法
var ppList = personList.Where(p => p.name == "a").Select(p => new { p.name, p.age, p.sex });
在查询语法中需要select子句,但在以前并没有看到Select()方法,因为在linq方法语法中不需要它,除非在进行投射。(改变结果集中所查询的原始类型)
方法调用的顺序不是固定的,因为linq方法调用返回的类型执行了ienumberable,可以在where()方法的结果上调用select()方法,反之亦然。但是,根据查询的特性,调用顺序也很重要。例如:
personList.Select(p => new { p.age, p.sex }).Where(p => p.name == "a");
这样是错误的,因为name属性不包含在select()投射创建的匿名类型(p.age,p.sex)中。
下面这样就OK:
personList.Select(p => new { p.age, p.sex }).Where(p => p.age== 1);
单值选择查询
distinct:该查询可搜索数据中的唯一值
方法语法:
var ppppList = personList.Select(p => p.name).Distinct();
查询语法:
var tList = (from p in personList select p.name).Distinct();
c#编辑器将查询语法转换为方法语法中的相同linq方法调用,所以如果对可读性和样式有意义,就可以混合和匹配它们。
Any()和All()
可以快速确定对于数据而言,某个条件是true还是false
列表是是否包含名字为a的,如果有就返回true
personList.Any(p=>p.name=”a”)
列表里是不是所有人的名字都是a,如果是的话返回true
personList.All(p=>p.name=”a”)
多级排序
from p in personlist orderby p.name,p.age,p.sex select new{p.name,p.age,p.sex}
//先按照name排序,再age,再sex
降序关键字:descending,如果需要某个值按降序排列,在对应字段后面添加此关键字。
如:orderby p.name descending,p.age,p.sex
多级排序方法语法:ThenBy
personlist.orderby(p=>p.name).thenby(p=>p.test).select(=>new{p.name,p.test});
降序语法:orderbydescending(),用此替换thenby
注意的地方:
1、必须先编写orderby,然后再编写thenby.
因为thenby()方法只能在iorderenumerable接口上使用。而此接口是由orderby()生成的
组合查询
from p in personlist group p by p.name into ppp
group p by p.name into ppp
select new{total=ppp.Sum(p=>p.sex),test=ppp.key};
from ppp in list1 orderby ppp.total descending select ppp
注意点:
1、组合查询中的数据通过一个键(key)字段来组合,每个组的所有成员都共享这个字段值。在这个例子中,键字段是name
2、要计算sex的总和,所以生成一个新的结果集ppp
3、select子句中,投射了一个新的匿名类型。其属性是通过总销量(通过引用ppp结果集来计算)和组的键字段值,后者是用特殊的组key来引用的。这个查询的是名字相同的sex值和。:)
4、按total字段对结果进行一个排序。
Take和Skip
take():从查询结果中提取钱n个结果
skip():其余的结果。
例如:
var result = from p in personlist orderby p.age descending select new {p.name,p.age};
result.take(5):返回age排名前5的结果集。
result.skip(5):返回除了前5之外的结果集。
first 和firstordefault
first:返回结果集中第一个匹配给定条件的元素
如:personlist.first(p=>p.name=”wxs”);
如果搜索条件不满足,firstordefault()会返回列表的默认元素,
而first()则会得到异常。
集运算符
集运算符要求集成员有相同的类型,才能确保得到希望的结果。
集运算符非常有用,但是用它们的实际优势因为受到所有对象的类型都是必须相同的限制而缩小了。
//顾客id结果集
var customerids = from c in customers select c.id
//订单ID结果集
var orderids = from o in orders selct o.id
//intersect
//查询在orderids结果集中有订单的顾客id,只有在两个结果集都有的id才包含在交集中,比如id=a,它既存在于customerids中,也存在于orderids中。
var cuustomerWithOrders = customerids.Intersect(orderids);
//except
//查询没有匹配顾客的订单id
var ordernocustomers = orderids.except(customerids);
//union
//查询所有顾客id和订单id字段的并集。删除了重复的项
var allcustomerorderids = orderids.union(customerids);
join
可用一个查询搜索2个列表中相关的数据,用键字段把结果连起来。类似
sql数据中的join操作。
var result = from c in customers join o in orders on c.id equals o.id
select new {c.id,c.city.salesbefore=c.sales,neworder=o.amount,salesafter=c.sales+o.amout};
//join通过customer类和order类的id字段,把每个顾客和其对应的订单连接起来。
//查询2个ID字段值相同的对象数据。