LINQ 学习之路

这篇具有很好参考价值的文章主要介绍了LINQ 学习之路。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、为什么要使用 LINQ

要理解为什么使用 LINQ,先来看下下面的例子

例子:要统计字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次和其出现的的频率。如果用传统的 Sql 语句来写,一定是非常的繁杂,如果用 LINQ 语句来写,效果如下

string strs = "hello word, Hehehe";
var items = strs.Where(c => char.IsLetter(c)) //过滤非字符
            .Select(c => char.IsLower(c))  //大小写都转换成小写
            .GroupBy(c => c) //根据字母进行分组
            .Where(g => g.Count() > 2) //过滤掉出现次数 <=2
            .OrderByDescending(g => g.Count()) //按次数排序
            .Select(g => new { Char = g.Key, Count = g.Count() });

使用 Linq 来实现,简单、清晰、明了。这里就体现了 LINQ 的一大好处:让数据处理变得简单

二、揭秘 LINQ 方法的背后

了解 LINQ 方法背后做了些什么,可以让我们更好的使用 LINQ。下面以 Wherr 方法为例,写一个我们自己的 MyWhere 方法

LINQ 提供了很多集合的扩展方法,配合 lambda 能简化数据处理

例子:有一个 [3, 15, 88, 4, 77, 42, 8] 的数组,要得到它 >10 的值

int[] num = new int[] { 3, 15, 88, 4, 77, 42, 8 };
//使用原本的Where
IEnumerable<int> result = num.Where(r => r > 10);
foreach (int i in result)
{
    Console.WriteLine(i);
});
}
static void Main(string[] args)
{
    int[] num = new int[] { 3, 15, 88, 4, 77, 42, 8 };
    //使用我们自己写的MyWhere方法
    var result2 = MyWhere2(num, r => r > 10);
    foreach (int i in result2)
    {
        Console.WriteLine(i);
    }           
}
public static IEnumerable<int> MyWhere(IEnumerable<int> items, Func<int, bool> f)
{
    List<int> result = new List<int>();
    foreach (var i in items)
    {
        if (f(i) == true)
        {
            result.Add(i);
        }
    }
    return result;
}

在上述代码中,MyWhere 方法是根据我们的需求来写的一个扩展方法,它要求传入一个IEnumerable 类型的参数和一个 Func<int,bool> 委托类型的参数,在方法中,新建一个 List 集合用于存值,遍历传入的数组,符合条件就存入集合中,最后返回集合。

三、LINQ 的扩展方法

LINQ 关键的功能是提供了集合类的扩展方法,所以实现了 IEnumerable 接口的类都可以使用这些方法,这是方法并不是 IEnumerable 中的方法,而是以扩展方法的存在于System.Linq 命名空间的静态类中

准备一些测试数据

class Employee
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public bool Gender { get; set; }
    public int Salary { get; set; }
    public override string ToString()
    {
        return $"Id={Id},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
    }
}

Where(数据过滤)

Where 方法是根据条件对数据进行过滤

语法如下:

IEnumerable<Employee> items = list.Where(e => e.Age > 25);
foreach (var item in items)
{
    Console.WriteLine(item);
}

Count(获取数据条数)

语法如下:

 //返回一个数字,表示指定序列中满足条件的元素个数。
 Console.WriteLine(list.Count(e => e.Salary > 5000 || e.Age > 25));

Any(判断是否有一条数据满足条件)

语法如下:

//是否至少有一条数据
//性能比 Count 要高,Count 会遍历所有数据才返回结果,Any 在遍历数据时遇到满足条件的数据就直接返回结果
Console.WriteLine(list.Any(e => e.Salary == 8000));
Console.WriteLine(list.Where(e=>e.Salary>8000).Any());

Single、SingleOrDefault、First、FirstOrDefault(获取一条数据)

语法如下:

//有且只有一条数据,如果没有符合条件的数据或者存在大于一条符合条件的数据,都会报错
Console.WriteLine(list.Single(s => s.Name == "张德开"));
//有且只有一条数据,返回该条数据,否则返回默认值,如果匹配到多条数据,则会报错
Console.WriteLine(list.SingleOrDefault(s => s.Age == 18));
//匹配到多条数据时,返回第一条数据,没有匹配到数据时,则会报错
Console.WriteLine(list.First(e => e.Age > 30));
//匹配到多条数据时,返回第一条数据,否则返回默认值
Console.WriteLine(list.FirstOrDefault(e => e.Age > 30));

OrderBy、OrderByDescending(排序)

语法如下:

 //升序排序
 IEnumerable<Employee> e = list.OrderBy(s => s.Age);
 //降序排序
 e = list.OrderByDescending(s => s.Salary);
 e = list.OrderByDescending(s => s.Name[s.Name.Length - 1]);
 //可以在OrderBy、OrderByDescending后面继续使用ThenBy、ThenByDescending进行多规则排序
 e = list.OrderBy(s => s.Age).ThenBy(s => s.Salary);
 foreach (var item in e)
 {
     Console.WriteLine(item);
 }

Sike()、Take()(限制结果集)

语法如下:

// Skip(n) 跳过 n 条数据,Take(n) 获取 n 条数据
var items2 = list.Skip(3).Take(2);
items2 = list.Where(e => e.Age >= 25).OrderBy(e => e.Age).Skip(2).Take(3);
foreach (var item in items2)
{
 Console.WriteLine(item);
}

聚合函数

Max(最大值)、Min(最小值)、Average(平均值)、Sun(总和)、Count(总数)

语法如下:

//最大年龄
Console.WriteLine(list.Max(e => e.Age));
//最低工资
Console.WriteLine(list.Min(e => e.Salary));
//平均工资
Console.WriteLine(list.Average(e => e.Salary));
//所有人总工资
Console.WriteLine(list.Sum(e => e.Salary));
//女员工数量
Console.WriteLine(list.Count(e => e.Gender == false));

GroupBy(分组)

GroupBy 方法的参数 keySelector 是分组条件表达式,GroupBy 方法的返回值为IGrouping<TKey, TSource> 类型的泛型 IEnumerable。IGrouping 是继承自 IEnumerable的接口,IGrouping 中唯一的成员就是 Key 属性,表示这一组数据的数据项,由于IGrouping 是继承自 IEnumerable 接口的,因此我们依然可以使用 Count、Min、Average等方法对组内数据进行聚合运算

语法如下:

 //根据年龄进行分组
 IEnumerable<IGrouping<int, Employee>> items3 = list.GroupBy(e => e.Age);
 foreach (IGrouping<int, Employee> g in items3)
 {
     Console.WriteLine(g.Key);
     foreach (Employee e in g)
     {
         Console.WriteLine(e);
     }
 }

综合案例:

//根据年龄分组,获取每组人数,最大工资,平均工资,用var简化编程
var item3 = list.GroupBy(e => e.Age);
foreach (var g in item3)
{
    Console.WriteLine("每组人数:" + g.Count());
    Console.WriteLine("最大工资:" + g.Max(e => e.Salary));
    Console.WriteLine("平均工资:" + g.Average(e => e.Salary));
    foreach (var e in g)
    {
        Console.WriteLine(e);
    }
}

Select(投影)

可以对集合使用 Select 方法进行投影操作,通俗来讲就是把集合中的每一项逐渐转换为另外一种类型,Select 方法的参数是转换的表达式。

语法如下:

//把集合中的每一项转换成另一个类型
var items4 = list.Select(e => e.Age);
//Select 方法把 bool 的 Gender 转换为字符串类型,Select 方法的返回值为 IEnumerable<string> 类型
var items4 = list.Where(e => e.Salary > 5000).Select(e => e.Gender ? "男" : "女");
//根据年龄分组,然后统计各组人数、年龄、最高工资、最低工资
var items4 = list.GroupBy(e => e.Age).Select(s => new { NianLing = s.Key, MaxS = s.Max(e => e.Salary), MinS = s.Min(e => e.Salary), RenShu = s.Count() });
foreach (var e in items4)
{
    Console.WriteLine(e.NianLing + ',' + e.MaxS + "," + e.MinS + ',' + e.RenShu);
}

集合转换

语法如下:

// ToList() 将其他类型转换为 List<T> 类型
List<Employee> empList = list.Where(e => e.Age > 25).ToList();
// ToArray() 将其他类型转换为数组
Employee[] empArr = list.Where(e => e.Salary > 5000).ToArray();

链式调用

上述介绍的这些方法,Where、Count、OrderBy、GroupBy 等方法的返回值都是 IEnumerable 类型,因此它们是可以链式调用的

//获取 id>2 的数据,然后按照 Age 分组,并且把分组按照 Age 排序,然后取出前三条,最后再投影取得年龄、人数、平均工资
var items5 = list.Where(e => e.Id > 2).GroupBy(g => g.Age).OrderBy(g => g.Key).Take(3)
                .Select(e => new { LianLin = e.Key, renShu = e.Count(), pingJun = e.Average(e => e.Salary) });
foreach (var i in items5)
{
    Console.WriteLine(i.pingJun + "," + i.renShu + "," + i.pingJun);
}

四、LINQ 的另一种写法

LINQ 有两种语法,分别为方法语法和查询语法

//方法语法:使用Where、OrderBy、Selsect等扩展方法来查询数据的写法叫做Linq方法语法
var items6 = list.Where(e => e.Salary > 3000).OrderBy(e => e.Age)
                .Select(e => new { e.Name, e.Age, XB = e.Gender ? "男" : "女" });
//查询语法:使用 LINQ 声明性查询语法编写的查询语句,在编译代码时,查询语法必须转换为针对.Net公共语言的的调用,这些方法的调用会调用标准查询运算符
var items7 = from e in list
             where e.Salary > 3000
             orderby e.Age
             select new
             {
                 e.Name,
                 e.Age,
                 XB = e.Gender ? "男" : "女"
             };

方法语法

“方法语法” 并没有发明新的语法,用的都是扩展方法、Lambda 表达式等 C# 中已经存在的语法,而 “查询语法” 则是新的 C# 语法 。编译器会把 “查询语法” 编译成 “方法语法” 形式,因此它们在运行时没有区别。所有的 “查询语法” 都能改写成 “方法语法”,所有的 “方法语法”也能改写成 “查询语法” 。

查询语法

“查询语法” 看起来更加新颖,而且比 “方法语法” 需要写的代码会少一点,但在编写复杂的查询条件的时候,用 “方法语法” 编写的代码会更清晰

五、小练习

练习一

"85,34,23,45,12,67,60" 计算这些数的平均值

 string s = "85,34,23,45,12,67,60";
 var avg = s.Split(',').Select(e => Convert.ToInt32(e)).Average();
 Console.WriteLine(avg);

练习二

统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和出现的频率文章来源地址https://www.toymoban.com/news/detail-663736.html

string s = "Hello word Hehehe Hahaha";
var items7 = s.Where(e => char.IsLetter(e)).Select(e => char.ToLower(e)).GroupBy(c => c)
    .Select(g => new { g.Key, Count = g.Count() }).OrderBy(g => g.Count).Where(g => g.Count > 2);
foreach (var item in items7)
{
    Console.WriteLine(item);
}

到了这里,关于LINQ 学习之路的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入理解 go reflect - 反射为什么慢

    我们选择 go 语言的一个重要原因是,它有非常高的性能。但是它反射的性能却一直为人所诟病,本篇文章就来看看 go 反射的性能问题。 在开始之前,有必要先了解一下 go 的性能测试。在 go 里面进行性能测试很简单,只需要在测试函数前面加上 Benchmark 前缀, 然后在函数体

    2024年02月01日
    浏览(47)
  • 为什么华为、阿里、字节跳动、微软等都走上了云原生和数字化之路?

    亲爱的开发者朋友们好哇, 前几天我发了篇文章,请各位朋友帮忙给最新一期的《新程序员》选封面,并且和大家说内容已经全部完成,即将出版和大家正式见面。今天,它来啦!《新程序员003:云原生和全面数字化实践》正式开启预售,现在下单,在元旦后将正式开放电子

    2024年02月05日
    浏览(58)
  • 【Linux(0)】为什么要学习Linux,为什么互联网公司在招聘时,会提出要有Linux经验,及其使用;一些Linux常见指令

    💓作者简介: 加油,旭杏,目前大二,正在学习 C++ , 数据结构 等👀 💓作者主页:加油,旭杏的主页👀 ⏩本文收录在:再识C进阶的专栏👀 🚚代码仓库:旭日东升 1👀 🌹欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖        在学习完C语言后,紧接着,我们要来 学习Li

    2024年02月05日
    浏览(64)
  • 白话理解TCP为什么一定要进行三次握手

    首先简单介绍一下TCP三次握手     在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同

    2024年02月08日
    浏览(50)
  • 为什么说 QUIC 协议是现代化网络通信的未来之路及如何实现QUIC服务器

    😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。😊 座右铭:不想当开发的测试,不是一个好测试✌️。 如果感觉博主的文章还不错的话,还请点赞、收藏哦

    2024年04月23日
    浏览(48)
  • 如何理解鲁棒性?为什么robustness会翻译为鲁棒性?

    鲁棒性,英文为Robustness(承受故障和干扰的能力),是许多复杂系统(包括复杂网络)的关键属性。复杂网络的鲁棒性研究对许多领域都非常重要。本文着重介绍了鲁棒性的基本定义、命名起源、分类区别、提升方法和具体应用,供大家学习参考。 1. 鲁棒性的基本定义 鲁棒

    2024年01月19日
    浏览(42)
  • K8s为什么需要calico? calico 原理深入理解.

    Status: Not Started Tags: 网络, 面试 Calico作为容器网络方案和我们前面介绍的那些方案最大的不同是它没有采用overlay网络做报文的转发,而是提供了 纯3层的网络模型. 三层通信模型表示每个容器都通过IP直接通信,中间通过路由转发找到对方。在这个过程中,容器所在的节点类似

    2024年02月16日
    浏览(45)
  • 分布式 - 谈谈你对分布式的理解,为什么引入分布式?

    不啰嗦,我们直接开始! 真正了解分布式系统的概念,日后工作中具有分布式系统设计思想。 能否在设计中对系统稳定性方面考虑周全。 能构建高 QPS 健壮的系统架构。 问题分析: 各种分布式框架层出不穷,Spring Cloud,阿里的 Dubbo,无论使用哪一个,原理都相同,考察下基

    2024年02月15日
    浏览(51)
  • 【C/C++】详解程序环境和预处理(什么是程序环境?为什么要有程序环境?如何理解程序环境?)

    目录 一、前言 二、 什么是程序环境? 三、 为什么要有程序环境? 四、如何理解程序环境? 🍎 ANSI C 标准  🍐 翻译环境和执行环境  五、详解翻译环境和执行环境  🍇翻译环境(重点!!)  💦编译环境(预处理---编译---汇编)  💦链接环境(链接)  🍉执行环境

    2024年02月21日
    浏览(61)
  • 为什么要学习算法

    我们每个人可能都会有过的经历: 是不是从学校开始,你就觉得数据结构难学,然后一直没认真学? 工作中,一遇到数据结构这个坑,你又发自本能地迅速避让,因为你觉得自己不懂,所以也不想深究,反正看起来无关大局? 当你想换工作面试,或者研究某个开源项目源码

    2024年02月01日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包