02020210 .NET Core重难点知识10-集合转换、链式调用、LINQ另一种查询形式、LINQ面试题
02020210 .NET Core重难点知识10-集合转换、链式调用、LINQ另一种查询形式、LINQ面试题
- 本章节笔记中,需要如下元数据
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo02
{
class Employee
{
public long Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Gender { get; set; }
public int Salay { get; set; }
public override string ToString()
{
return $"Id = {Id}, Name = {Name}, Age = {Age}, Gender = {Gender}, Salary = {Salay}";
}
}
class Program
{
static void Main(string[] args)
{
List<Employee> list = new List<Employee>();
list.Add(new Employee { Id = 1, Name = "jerry", Age = 28, Gender = true, Salay = 5000 });
list.Add(new Employee { Id = 2, Name = "jim", Age = 33, Gender = true, Salay = 3000 });
list.Add(new Employee { Id = 3, Name = "lily", Age = 35, Gender = false, Salay = 9000 });
list.Add(new Employee { Id = 4, Name = "lucy", Age = 16, Gender = false, Salay = 2000 });
list.Add(new Employee { Id = 5, Name = "kimi", Age = 25, Gender = true, Salay = 1000 });
list.Add(new Employee { Id = 6, Name = "nancy", Age = 36, Gender = false, Salay = 8000 });
list.Add(new Employee { Id = 7, Name = "zack", Age = 35, Gender = true, Salay = 8500 });
list.Add(new Employee { Id = 8, Name = "jack", Age = 33, Gender = true, Salay = 8000 });
}
}
}
1. 集合转换(视频Part2-21)
- 有一些地方需要数组类型或者List类型的变量,我们可以用ToArray方法和ToList分别把IEnumerable
转换为数组类型和List 类型。
IEnumerable<Employee> items1 = list.Where(e => e.Salay > 6000); // @1 获取可迭代类型
List<Employee> list1 = items1.ToList(); // @2 将@1处可迭代类型转为List类型
Employee[] array1 = items1.ToArray(); // @3 将@1处可迭代类型转为数组类型
2. 链式调用
- Where、Select、OrderBy、GroupBy、Take、Skip等返回值都是IEnumerable
类型,所以可以链式调用。
// 示例:获取Id > 2的数据,然后按照Age分组;并且把分组按照Age排序,然后取出前3条;最后在投影获取年龄,人数,平均工资。
static void Main(string[] args)
{
var items = list.Where(e => e.Id > 2).GroupBy(e => e.Age).OrderBy(g => g.Key).Take(3).Select( // @1
g => new { NL = g.Key, RS = g.Count(), PJ = g.Average(e => e.Salay)}); // @2
foreach (var it in items)
{
Console.WriteLine(it.NL + "," + it.RS + "," + it.PJ);
}
Console.ReadLine();
}
控制台输出:
16,1,2000
25,1,1000
33,1,8000
说明:
1. GroupBy方法返回的是[(key, e)]这种集合类型
2. 在@1处,GroupBy返回的是IEnumerable<IGrouping<int, Employee>>,后面接的OrderBy是对GroupBy返回的类型进行排序,即此时要对key进行排序。
3. 在@2处,关注一下每个方法返回值的类型,便于理解。
- 老师在此提出一个观点,多看几遍,多看看返回值类型,理解之后跟着学,坚持往下看。我个人觉得还好,能理解。
3. LINQ另一种倩影(视频Part2-22)
3.1 LINQ方法语法与LINQ查询语法
- 使用Where、OrderBy、Select等扩展方法进行数据查询的写法佳作“LINQ方法语法”。
- 如下代码段,是一种称为"查询语法"的写法。
// LINQ查询语法
var items2 = from e in list // @1
where e.Salary > 3000
orderby e.Age
select new {e.Name, e.Age, Gender = e.Gender? "男" : "女"};
说明:
1. 本代码段中这种写法在LINQ刚出现的时候大家比较喜欢实用,但是后续发现还是"LINQ方法语法"这种写法更好用。
2. 查询语法是专门为LINQ而生的,它让写LINQ语句更像写SQL语句一样。
3. 在@1处,使用元素e遍历list,然后把每个e元素按照where、orderby、select来进行处理。注意,这些都是C#里自带的语法,并不是SQL里面的语法。
3.2 两种查询方式对照
static void Main(string[] args)
{
// @1 使用LINQ方法语法
var items1 = list.Where(e => e.Salay > 3000).OrderBy(e => e.Age).Select(
e => new { e.Age, e.Name, XB = e.Gender ? "男" : "女" });
foreach (var it in items1)
{
Console.WriteLine(it);
}
Console.WriteLine("**********************************");
// @2 使用LINQ查询语法
var items2 = from e in list
where e.Salay > 3000
select new { e.Age, e.Name, XB = e.Gender ? "男" : "女" };
foreach (var it in items2)
{
Console.WriteLine(it);
}
Console.ReadLine();
}
控制台输出:
{ Age = 28, Name = jerry, XB = 男 }
{ Age = 33, Name = jack, XB = 男 }
{ Age = 35, Name = lily, XB = 女 }
{ Age = 35, Name = zack, XB = 男 }
{ Age = 36, Name = nancy, XB = 女 }
**********************************
{ Age = 28, Name = jerry, XB = 男 }
{ Age = 35, Name = lily, XB = 女 }
{ Age = 36, Name = nancy, XB = 女 }
{ Age = 35, Name = zack, XB = 男 }
{ Age = 33, Name = jack, XB = 男 }
说明:
1. 在@1处和@2处的两种查询方式,输出的结果是一样的。
2. 这两种语法,编译器编译之后的结果也是一样的,可以理解为两种查询形式是等价的。
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// 事实上,用反编译器可以发现,如下代码
var items1 = list.Where(e => e.Salay > 3000).OrderBy(e => e.Age).Select(
e => new { e.Age, e.Name, XB = e.Gender ? "男" : "女" });
// 会被反编译为
var items1 = from e in list
where e.Salay > 3000
select new { e.Age, e.Name, XB = e.Gender ? "男" : "女" };
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
综上:
1. 上述两种形式在源码上看着不同,但是反编译后完全等价。
2. 查询语法看起来更酷,但是方法语法更实用,因此.NET开发者大部分还是用方法语法。
3. LINQ解决面试问题(视频Part2-23)
3.1 LINQ性能
- LINQ大部分时间不会影响性能,在老师做过的项目里面,几乎没有遇到过因为LINQ导致性能不够的情况。
- 不过有一个地方曾经出现过:将视频的背景进行抠图,这个涉及到对每一个像素点进行操作,此时需要取出当前像素RGB的最大值,用LINQ来操作。代码段如下所示
int i = 5;
int j = 8;
int k = 6;
int[] nums = new int[] { i, j, k };
int max = nums.Max(); // 使用LINQ来实现取出数组的最大值
Console.WriteLine(max);
- 用上述方式之后,界面特别的卡。此时考虑使用Math方法,界面刷一下就流畅了。
int i = 5;
int j = 8;
int k = 6;
int max = Math.Max(i, Math.Max(j, k)); // 使用Math方法来实现取出最大值
- 最高性能实现形式,使用三元运算符,或者最土的判断语句来实现,代码段如下。
int max = i > j? i : j > k ? i > j ? i : j : k;
- 图形处理对运算速度的要求太快了,因为每个像素点都要进行操作。
- 此时如果使用LINQ,需要构建数组,然后对数组进行Max方法调用,此时性能会低一点。
- 采用Math或者三元运算,这样没有多余的操作,性能就会高一些。
- 总结:对项目开发来讲,用LINQ是没有问题的,除非极少数特殊应用场景。
3.2 LINQ面试
- 面试时候的算法题一般尽量避免使用正则表达式,LINQ等这些高级的类库。大饭店面试大厨的故事。
- 面试是算法一般都要求用循环、判断、数组等这些基本的东西来实现,不建议使用正则、LINQ等这些高级的特性来实现。
- 虽然用高级特性可以很快将一个高级特性做出来,但是这体现不出来个人的水平。LINQ等这些是框架帮你完成的事情,不是你个人的水平。
- 大饭店面试大厨,是让你做蛋炒饭,水煮白菜,这才能体现一个人真正的水平。而鲍鱼龙虾本身就是好的食材,做出来本身就不会差。
3.3 面试题
- 面试题1:用一个逗号分隔的表示成绩的字符串,然后计算平均值。
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo02
{
class Program
{
static void Main(string[] args)
{
// 形式1:使用LINQ分步骤来写
string s = "61,90,100,99,18,22";
string[] strs = s.Split(","); // @1.1 拿到string类型的数组
IEnumerable<int> nums = strs.Select(e => Convert.ToInt32(e)); // @1.2 使用投影将stirng类型数组转换为int类型的可迭代对象。
double avg1 = nums.Average(); // @1.3 获取平均值
Console.WriteLine(avg1);
// 形式2:使用LINQ链式编程
double avg2 = s.Split(",").Select(e => Convert.ToInt32(e)).Average();
Console.WriteLine(avg2);
Console.ReadLine();
}
}
}
控制台输出:
65
65
- 面试题2:统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的字符和其出现的频率。
using System;
using System.Linq;
namespace Demo02
{
class Program
{
static void Main(string[] args)
{
string s = "hello world, hahaha, heiheihei"; // string实现了IEnumerable<char>接口。
var items = s.Where(c => char.IsLetter(c)).Select(c => char.ToLower(c)) // 先过滤获取所有字符,然后将字符通过映射转换为小写
.GroupBy(c => c) // 根据字符来分组
.Select(g => new { g.Key, Count = g.Count() }) // 通过投影统计出现评率
.OrderByDescending(g => g.Count) // 通过字符出现的次数排序
.Where(g => g.Count > 2); // 过滤出现频率大于2次的字符
foreach (var it in items)
{
Console.WriteLine(it);
}
Console.ReadLine();
}
}
}
控制台输出:
{ Key = h, Count = 7 }
{ Key = e, Count = 4 }
{ Key = l, Count = 3 }
{ Key = a, Count = 3 }
{ Key = i, Count = 3 }
说明:能自己写出本题的代码,那么LINQ等于毕业了。
结尾
书籍:ASP.NET Core技术内幕与项目实战
视频:https://www.bilibili.com/video/BV1pK41137He
著:杨中科
ISBN:978-7-115-58657-5
版次:第1版
发行:人民邮电出版社
※敬请购买正版书籍,侵删请联系85863947@qq.com※
※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

浙公网安备 33010602011771号