- LINQ的意义:可以是数据处理变的简单
- LINQ的由来,从lambda表达式,指向了一个匿名方法
- LINQ.Where()方法实现: static IEnumerable
MyWhere(this IEnumerable source,Func func){ foreach(var item in source){ if(fun(item)){yield return item;}} - LINQ常用的扩展方法:
- Where查询语句
- Count计数
- Single First 满足条件
- Order 排序
- Skip Take 跳过取
- 聚合函数
- 分组GroupBy IGrouping
- Select投影操作,把数据投影到自己想要的实例上,支持匿名类型
- 查询语法 from item in list orderby xxxx等
LINQ的意义
让数据处理变的简单,和python中NumPy类库功能相似。委托(Action Func—lambda-linq ```csharp
static void Main(string[] args){ string s = “adbdfaghagkaewqrwosfbafaof1214afhkaf”; var items = s.Where(c => char.IsLetter(c))//过滤非字母 .Select(c => char.ToUpper(c))//全部转换为大写 .GroupBy(c => c)//根据字母进行分组 这里变成了类似字典的东西 .Where(g => g.Count() > 2)//过滤掉出现次数<=2的字符 .OrderByDescending(g => g.Count())//按次序降序排序 .Select(g => new { Char = g.Key, Count = g.Count() }); foreach (var item in items) { Console.WriteLine(item.Char); Console.WriteLine(item.Count); } }
delegate void TestDelegate(); //委托是一个类型,需要创建实例,同步调用、异步调用(容易造成资源竞争) TestDelegate testDelegate = new TestDelegate(F1); testDelegate = F1;//这样直接赋值也可以,委托testDelegate指向F1方法,方法的指针,方法模板。 testDelegate.Invoke();
static void F1(){ Console.WriteLine(“我是F1”); }
<a name="DHP7u"></a>
# Lambda 委托指向匿名方法
委托指向匿名方法(lambda)
- 如果=>之后的方法体中**只有一行代码**,且方法有返回值,可以省略大括号和return
- 如果**只有一个参数**()可以省略
```csharp
Func<int,int,string> f1 = delegate(int i1,int i2){return $"{i1}+{i2}={i1+i2}";}
string s = f1(1,2);
//演变
Func<int, int, string> func = (a, b) => { return $"{a + b}"; };
Console.WriteLine(func(1,2));
//省略(只有一行代码)
Func<int, int, string> func = (a, b) =>$"{a + b}";
Console.WriteLine(func(1,2));
//省略(只有一个参数)
Func<int, string> func = a=>$"{a}";
Console.WriteLine(func(1,2));
自我实现LINQ.Where
var nums = new int[] { 1, 2, 3, 54, 643, 63, 7, 78 };
var tmp = nums.Where(i => i > 10);
tmp = MyWhere(nums,a=>a>10);
tmp = nums.MyWhereKuo(a=>a>10);
static IEnumerable<int> MyWhere(IEnumerable<int> items,Func<int,bool> func)
{
foreach (var item in items)
{
if (func(item))
{
yield return item;
}
}
}
//扩展方法:public static修饰,this关键字,this后的类型都可以.出来此静态方法 包含扩展方法的类
必须是静态类
public static IEnumerable<int> MyWhereKuo(this IEnumerable<int> items,Func<int,bool> func)
{
foreach (var item in items)
{
if (func(item))
{
yield return item;
}
}
}
LINQ常用扩展方法
LINQ中提供了大量类似Where的扩展方法,简化数据处理。大部分都在System.Linq命名空间中。
Where方法:查询
public static IEnumerable
Lambda:委托指向匿名方法
这里面枚举迭代source内容,泛型委托,当方法满足这个泛型委托约束即可(匿名方法)传入迭代的元素,返回值为bool类型,用于判断条件是否满足。
using System;
using System.Collections.Generic;
namespace AlbertLINQ
{
public static class Program
{
static void Main(string[] args)
{
List<Student> stuList = new List<Student>(){
new Student(){Name="Albert",Age=24,Height=175},
new Student(){Name="Jack",Age=22,Height=180},
new Student(){Name="Doris",Age=28,Height=165}
};
var stuSortList = stuList.AlbertWhere(x=>x.Age>25);
foreach(var item in stuSortList){
System.Console.WriteLine(item.Name);
}
}
static IEnumerable<TSource> AlbertWhere<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> func){
foreach(var item in source){
if(func(item)){
yield return item;
}
}
}
}
public class Student{
public string Name { get; set; }
public int Age { get; set; }
public double Height { get; set; }
}
}
Count()方法:获取满足条件的数据条数
两种写法:
//写法一:直接Count
int count = list.Count(a=>a.Age<30);
//写法二:先Where筛选后再Count
int countTwo = list.Where(a=>a.Age<30).Count();
public static int Count<TSource>(this IEnumerable<TSource> source)
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
Any()方法:是否至少有一条数据(比Count后再比较效率高)
List<Student> stuList = new List<Student>()
{
new Student(){Age=24,Name="Albert",Height=176},
new Student(){Age=25,Name="Jack",Height=178},
new Student(){Age=28,Name="Doris",Height=165}
};
var anyList = stuList.Any();
Console.WriteLine(anyList); //True
anyList = stuList.Any(x => x.Age > 36);
Console.WriteLine(anyList);//False
Single() SingleOrDefault() First() FirstOrDefault() 获取一条数据(是否带参数的两种写法)—防御性编程(避免问题越来越大)
Single:有且只有一条满足要求的数据(唯一一个 SingleDog单身狗) 不能返回默认值,必须有一条 =1
SingleOrDefault:最多只有一条满足要求的数据 <=1
First:至少有一条,返回第一条 不能返回默认值,必须有一条 >=1
FirstOrDefault:返回第一条或者默认值
Order() 排序
Order():对数据正序排序
OrderByDescending()倒叙排序
//倒序排序
var stuSortList2 = stuList.OrderByDescending(e => e.Age);
//随机排序
var stuSortList3 = stuList.OrderByDescending(e => Guid.NewGuid());
多规则排序
ThenBy()
ThenByDescending()
var stuSortList4 = stuList.OrderByDescending(e =>e.Name[e.Name.Length-1]).ThenBy(
e=>e.Height);
Skip() Take() 限制结果集,获取部分数据—用于分页
Skip(n)跳过n条数据,Take(n)获取n条数据
获取从第二条数据开始的三条数据 var orderedItem = list.Skip(2).Take(3);
var stuSortList5 = stuList.OrderByDescending(e => e.Name[e.Name.Length - 1]).ThenBy(
e => e.Height).Skip(2).Take(2);
聚合函数 Max() Min() Average() Sum() Count()
LINQ中所有扩展方法几乎都是针对IEnumerable接口的,而几乎所有能返回集合的都返回IEnumerable,所以是可以把几乎所有方法“链式使用”的。
var stuSortList6 = stuList.Max(e => e.Age);//返回年龄集合年龄的最大值
分组 GroupBy()
GroupBy()方法参数是分组条件表达式,返回值为IGrouping
排序后foreach取到的Item是IGrouping
List<Student> stuList = new List<Student>()
{
new Student(){Age=24,Name="Albert",Height=176},
new Student(){Age=25,Name="Jack",Height=178},
new Student(){Age=28,Name="Doris",Height=165},
new Student(){Age=24,Name="Lucy",Height=176},
new Student(){Age=25,Name="Boris",Height=180},
new Student(){Age=28,Name="Dobin",Height=169}
};
var groupStu = stuList.GroupBy(x => x.Age);
foreach (var item in groupStu)
{
//外层循环获取到的是IGroup对象,里面有的是IGrouping<int,Student> int是Key值,分组的K值
Console.WriteLine(item.Key);
Console.WriteLine(item.Max(g=>g.Height));//每一组是一个集合,是集合就可以用聚合函数,这边把
//每一组里面的身高最大值取出来
Console.WriteLine(item.Average(g=>g.Height));//平均身高
foreach (var stu in item)
{
Console.WriteLine(stu.Name);
}
Console.WriteLine("===========");
}
Console.ReadLine();
投影操作 Select
把集合中的每一项转换为另外一种类型。
var stuSelect = stuList.Select(e => e.Age+""+e.Height);//将所有的Age+Height取出来 IEnumerable<sting>
var stuSelect2 = stuList.Select(e => e.Age);//将所有的Age取出来 IEnumerable<int>
var stuSelect3 = stuList.Where(e=>e.Age>25).Select(e => e.Age+","+e.Height);//将所有的Age取出来
匿名类型—在编译时生成,ILSpy
var p = new {Name=”Tom”,Id = 1}
var stuSelect3 = stuList.Select(e => new { Name = "YangZhongKe", Age = 50 });//匿名类型
foreach (var item in stuSelect3)
{
Console.WriteLine(item.ToString());
}
//打印结果,stuList长度为6,每一个都替换成new出来的匿名类型
{ Name = YangZhongKe, Age = 50 }
{ Name = YangZhongKe, Age = 50 }
{ Name = YangZhongKe, Age = 50 }
{ Name = YangZhongKe, Age = 50 }
{ Name = YangZhongKe, Age = 50 }
{ Name = YangZhongKe, Age = 50 }
集合转换
ToArray() ToList()分别把IEnumerable
查询语法—掌握方法语法即可
var item = from e in list
where e.Salary>3000
orderby e.Age
select new{e.Name,e.Age,Gender=e.Gender?”男”:”女”};
LIQN面试问题
面试时候的算法题一般避免使用正则表达式、LINQ等这些高级的类库。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ApplyLINQ
{
class Program
{
static void Main(string[] args)
{
CaseOne();
CaseTwo();
Console.ReadLine();
}
//有一个用逗号分隔的表示成绩的字符串,如"61,90,100,
//99,18,22,38,66,80,93,55,50,89
//计算这些成绩的平均值
static void CaseOne()
{
string str = "61,90,100,99,18";
var average = str.Split(',').Average(e => int.Parse(e));
Console.WriteLine(average);
}
//统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出
//出现频率高于2次的单词和其出现频率
static void CaseTwo()
{
string str = "abcdabcdabcAaBczdhkguiahgadklg";
var tmp = str.ToUpper().GroupBy(c => c);
foreach (var value in tmp)
{
Console.WriteLine(value.Key);
Console.WriteLine(value.Count());
foreach (var value2 in value)
{
Console.WriteLine(value2);
}
Console.WriteLine("============");
}
Console.WriteLine("xxxxxxxxxxx");
var word = str.ToUpper().GroupBy(c => c).Select(g => new { DC = g.Key, PL = g.Count() }).
OrderByDescending(c => c.PL).Where(c => c.PL > 2);
foreach (var item in word)
{
Console.WriteLine(item.ToString());
}
}
}
}