C#基础_学习笔记--LINQ初识
LINQ初识
为什么要学LINQ?
为了让数据处理变得简单。
在写.net core 后端应用时,采用EFCore对数据库进行操作,Linq使用频率很高,所以在此补充学习Linq的基础。
举例:统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率。
LINQ的效率不一定高,但用起来会很简单,省去了很多循环代码。
var items = s.Where(c =>char.IsLetter(c))//过滤非字母
.Select(c => char.ToLower(c))//大写字母转换为小写
.GroupBy(c => c)//根据字母进行分组
.Where(g => g.Count() > 2)//过滤掉出现次数<=2
.OrderByDescending(g => g.Count())//按次数排序
.Select(g=>new{Char=g.Key,Count=g.Count()});
原理:
委托-->lambda-->LINQ
LINQ1:委托
- 委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法。
举例:int i= 5;
- int是整数类型,i是整数类型的变量,5是整数类型的数据;
- 整数类型的变量i指向5这个整数类型的数据;
- 委托是方法的类型;
同样的,来理解委托:
delegate void D1();//申明D1类型的委托
delegate int D2(int i1,int j1);//带参数
class Program
{
static void Main(string[] args)
{
D1 d = F1; //D1类型的d指向F1方法
d();//执行
D2 d2 = Add;
Console.WriteLine(d2(3,5));//结果为8
}
static void F1()
{
Console.WriteLine("我是F1");
}
static int Add(int i1,int i2)
{
return i1 + i2;
}
}
- .NET中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型;
举例:
Action a1 = F1;
a1(); //结果:“我是F1”
//Func<in T, out TResult>(T arg)
//Func的最后一个参数是返回值,前面的都是输入参数
Func<int,int,int> f = Add;
Console.WriteLine(f(5,8));//结果为13
LINQ2:Lambda表达式
委托变量不仅可以指向普通方法,还可以指向匿名方法。
这里的匿名方法用delegate来声明;
Func<int,int,string> f1 = delegate(int i1,int i2){
return $"{i1}+{i2}={i1+i2}";
}
string s= f1(1,2);
还可以用lambda表达式来写匿名方法:
Func<int,int,string> f1 = (i1,i2)=>{
return $"{i1}+{i2}={i1+i2}";
}
//可以省略参数数据类型,因为编译能根据委托类型推断出参数的类型,用=>引出来方法体。
LINQ3:揭秘LINQ方法的背后
linq中提供了很多集合的扩展方法,配合lambda能简化数据处理;
举例:
先引用using System.Linq;不然无法使用where;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Linqex
{
class Program
{
static void Main(string[] args)
{
int[] nums = new int[] {3,5,353,6235,21,7 };
//where方法会遍历集合中每个元素,对于每个元素
//都调用a=>a>30这个表达式判断一下是否为true
//如果为true,则把这个放到返回的集合中
//这里的where是扩展方法,不是数组的方法
IEnumerable<int> result = nums.Where(x => x > 30);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
}
//结果
//353
//6235
//找出了大于30的集合
根据上面的linq语法,自己实现上面的功能:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Linqex
{
class Program
{
static void Main(string[] args)
{
int[] nums = new int[] {3,5,353,6235,21,7 };
//IEnumerable<int> result = nums.Where(x => x > 30);
IEnumerable<int> result = myWhere1(nums, a => a > 30);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
//遍历IEnumerable的items,调用f的委托,判断为true,则返回到结果的集合中
static IEnumerable<int> myWhere1(IEnumerable<int> items,Func<int,bool> f)
{
List<int> result = new List<int>();
foreach (var item in items)
{
if (f(item) == true)
{
result.Add(item);
}
}
return result;
}
}
}
//结果与用linq语法相同
用yield来实现返回
static IEnumerable<int> myWhere2(IEnumerable<int> items, Func<int, bool> f)
{
foreach (var item in items)
{
if (f(item) == true)
{
yield return item;
}
}
}
//结果一样
//用yield一边获取数据,一边处理数据,效率更高
可以使用var让编译器的“类型推断”来简化类型的声明。在LINQ中常用。
C#的var会根据变量的赋值推断出类型,在编译后会变为实际的类型。
C#的var和JavaScript的var不一样,仍然是强类型的。
C#中的弱类型是dynamic。
下一节:LINQ的常用扩展方法