c#入门-查询表达式

Linq

语言集成查询 (LINQ),是.NET做出来的一种,希望在程序中能实现类似于数据库查询的功能。

在数据库中,假如一个库的数据有1000G数据。希望在其中找出一个名字叫张三的人。
如何查找呢?这么庞大的数据量是不可能全在程序运行时加载进内存。
所以他会分片。一次只读取一块数据,如果满足就留下放到内存,如果不满足就读下一块数据。

c#中的Linq类似于此效果。
如果你只要求找出符合条件的一个数据。
那么Linq一旦找到了一个数据,就会终止对数据的遍历。以此达到优化。
虽然手写for循环,再进行一点操作也能达到这样的效果。
但是使用Linq达到同样的效果更简便。

查询表达式(常用部分)

一个最简单的查询表达式长这样

int[] p = { 1, 2, 3, 4, 5 };
var e = from a in p select a * a;

这个表达式返回的值是IEnumerable类型,可以使用foreach遍历。

foreach (var item in e)
{
	Console.WriteLine(item);
}

查询表达式中声明的标识符,作用域仅限于这个查询表达式。

获取数据源

表达式中的from a in p是说,从变量p中遍历元素。把p中的元素称为a。
其中,数据源必须实现IEnumerable接口,而不像foreach只需要有个GetEnumerator方法。

映射

表达式中的select a*a是对元素进行映射。
可以理解为,把元素a进行以下操作(a*a),得到的结果组合成一个新序列。

查询表达式中必须以映射或分组结尾。

筛选

int[] p = { 1, 2, 3, 4, 5 };
var e = from a in p
		where a > 3 || a % 2 == 0
		select a * a;

where子句可以筛选元素。
如果元素不满足条件,那么不会再经过后续的操作。

例如,序列中的1,3不满足条件,不会被映射,也就不会出现在结果序列中。

排序

int[] p = { 1, 6, 2, 5, 3 };
var e = from a in p
		where a > 3 || a % 2 == 0
		orderby a
		select a * a;

orderby子句会根据元素映射出来的键进行排序。
这个临时映射的键只作用于这次排序的操作,不会影响最后查询的结果。

orderby子句默认以升序排序(从小开始,越往后越大)
如果要改为降序排序,在键的映射后加descending

string[] s = { "hello", "WWW.com", "baidu", "remove" };
var des = from a in s
		  orderby a.Length descending
		  select a;

如果有多个排序条件,请使用元组或匿名类。
直接再次使用orderby子句会打乱已经排好的顺序。

string[] s = { "hello", "WWW.com", "baidu", "remove" };
var des = from a in s
		  orderby (a.Length, a[0]) descending
		  select a;

查询表达式(剩余部分)

延续

一个查询表达式在映射或分组后就结束了。
如果还需要继续查询,需要把映射或分组后的结果值声明为新的临时值。

string[] s = { "hello", "WWW.com", "baidu", "remove" };
var des = from a in s
		  select new { len = a.Length, fir = a[0] } into b
		  orderby b.len descending
		  select b.fir;

临时值

let 可以创建一个临时值。
可以代替映射元组。

string[] s = { "hello", "WWW.com", "baidu", "remove" };
var des = from a in s
		  let len=a.Length
		  let fir = a[0]
		  orderby len descending
		  select fir;

分组

分组查询会返回一个 IGrouping类型的序列。
这个接口继承IEnumerable,而比他多出来的属性只有一个:Key
这个Key是这个序列中共有的键。

string[] s = { "hello", "WWW.com", "baidu", "remove" };
var des = from a in s
		  orderby a.Length
		  group a by a.Length;
		  
foreach (var item in des)
{
	Console.WriteLine("接下来的元素的公有键是"+item.Key);
	foreach (var item2 in item)
	{
        Console.WriteLine(item2);
    }
    Console.WriteLine();
}

在group子句中,by指示分组依据。
例如hello和baidu的Length属性都是5。
那么他们就会被分到同一个IGrouping中。
并且这个IGrouping的Key值会赋值为5。

group a by a.Length中的a也表示一个映射。
在分完组后返回的值就是IGrouping了,没法直接操控里面的元素了。
分组中的映射是最后直接控制元素的时机。

联表

如果两个序列中有关联数据。
使用联表可以把这两个序列合并成一个序列。

假如一个老师拿到了附近网吧的登记单,想从中找出自己学生的上网情况。

class 学生
{
	public string 姓名;
	public string 身份证号;
}
class 网吧登记名单
{
	public string 身份证号;
	public int 机位;
}
学生[] 班级名单 = new 学生[]
{
	new 学生{ 姓名="张三" ,身份证号="186" },
	new 学生{ 姓名="李四" ,身份证号="103" },
	new 学生{ 姓名="王五" ,身份证号="197" },
	new 学生{ 姓名="赵六" ,身份证号="208" }
};

网吧登记名单[] 极速网吧 = new 网吧登记名单[]
{
	new 网吧登记名单{ 身份证号="103" ,机位=47 },
	new 网吧登记名单{ 身份证号="197" ,机位=36 },
	new 网吧登记名单{ 身份证号="248" ,机位=33 },
	new 网吧登记名单{ 身份证号="103" ,机位=32 }
};
var t = from a in 班级名单
		join b in 极速网吧 on a.身份证号 equals b.身份证号
		select a.姓名;

join子句中,前半段和from一样,都是指示数据源并对元素命名。
后半段是指示关联关系。这里是要求a的身份证号和b的身份证号对应。
这里面的equals是一个关键字。他的意思是你的Equals方法可能乱写,不能用。
他要使用linq自己的判断方法。

如果一个元素可以和多个元素匹配,那么会生成多个组合元素。例如:

string[] 花色 = { "黑桃","红桃","梅花","方片"};
string[] 点数 = { "A","2","3","4","5","6","7","8","9","10","J","Q","K"};

var p = from a in 花色
		join b in 点数 on 1 equals 1
		select a + b;

由于equals关系式用了两个和元素无关的量,使得恒成立。
最后每个元素之间都会配对出一个组合值。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值