C# .Net 5.0 LINQ


(仅用于学习笔记)

一,为什么学习LINQ

1.为什么要学LINQ?让数据处理变得简单

统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率。

委托→lambda→LINQ

2.委托是什么

1、委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法举例。

using System;

namespace asTest
{
    class Program
    {
        static void Main(string[] args)
        {
            D1 d = A;
            d();
            d = B;
            d();
            D2 d2 = Add;
            Console.WriteLine(d2(3, 5));
        }
        static void A()
        {
            Console.WriteLine("我是A");
        }
        static void B()
        {
            Console.WriteLine("我是B");
        }
        static int Add(int i,int j)
        {
            return i + j;
        }
    }
    //声明委托
    delegate void D1();
    delegate int D2(int i, int j)}

2、.NET 中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。举例。

 			Action a = A;
            a();
            Func<int,int,int>f = Add;
            Console.WriteLine(f(10, 2));
             Func<int, int, string> c = C;
            Action<int, string> d1 = D;

	
			static string C(int i, int j)
	        {
	            return "xxx";
	        }
	        static void D(int i,string s)
	        {
	            
	        }

二,lambda是怎么来的

1.委托变量不仅可以指向普通方法,还可以指向匿名方法。

2.匿名方法可以写成lambda表达式
3.可以省略参数数据类型,因为编译能根据委托类型推断出参数的类型,用=>引出来方法体。

4.如果委托没有返回值,且方法体只有一行代码,可省{}

5.如果=→>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的以及return。
6. 如果只有一个参数,参数的()可以省略。

static void Main(string []args)
        {
        //如果委托没有返回值,且方法体只有一行代码,可省{}

             Action a1 = delegate ()
              {
                  Console.WriteLine("wwww");
              };
               a1();
			  Action a11 = delegate ()=>
              Console.WriteLine("wwww");
              a11();
              
				
            Action<string, int> a2 = delegate (string n, int i)
               {
                   Console.WriteLine($"n={n},i={i}");
               };
            a2("af", 32);
            Func<int, int, int> a3 = delegate (int i, int j)
                 {
                     return i + j;
                 };
            Console.WriteLine(a3(2, 2));
  			 //lambda表达式
            Func<int, int, int> a4 = (int i, int j) =>
                {
                    return i + j;
                };
            Console.WriteLine(a4(2, 2));
            //可以去掉参数
            Func<int, int, int> a5 = (i, j) =>
                {
                    return i + j;
                };
            Console.WriteLine(a5(2, 2));
            
            //如果=→>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的以及return。
		  			Func<int, int, int> a51 = (i, j) =>
		                    i + j;
		            Console.WriteLine(a51(2, 2));
		            
		        //如果只有一个参数,参数的()可以省略。
            Action<int> a6 = (i) => Console.WriteLine(i);
            a6(6);
            Action<int> a61 = i => Console.WriteLine(i);
            a61(6);

            Func<int, bool> a62 = delegate (int i) { return i > 0; };
            Console.WriteLine(a62(5));

            Func<int, bool> a63 =i=> i > 0;
            Console.WriteLine(a63(5));

        }

三,LINQ方法的背后

LINQ中提供了很多集合的扩展方法,配合lambda能简化数据处理。
可以使用var让编译器的“类型推断”来简化类型的声明。在LINQ中常用。
C#的var和JavaScript的var不一样,仍然是强类型的。
(*)C#中的弱类型是dynamic。

using System;
using System.Collections.Generic;
using System.Linq;

namespace LInq1
{
    class Program
    {
        static void Main(string[] args)
        {
        //c#匿名类型
            int[] nums = new int[] { 3, 5, 33, 55, 355, 222, 3, 10, 9 };
            //where方法会遍历集合中的每个元素,判断
            IEnumerable<int> result = nums.Where(a => a > 40);
            //使用自定义方法
            IEnumerable<int> result = MyWhere1(nums, a => a > 10);
            //用var
 var result = MyWhere1(nums, a => a > 10);

            foreach(int i in result)
            {
                Console.WriteLine(i);
            }
        }
        //自定义方法
        static IEnumerable<int> MyWhere1(IEnumerable<int> items,Func<int,bool>f)
        {
            List<int> result = new List<int>();
            foreach(int i in items)
            {
                if(f(i)==true)
                {
                    result.Add(i);
                }

            }
            return result;
        }
    }
}
//第二种方法
    static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
        {
            foreach (int i in items)
            {
                if (f(i) == true)
                {
                    yield return i;
                }
            }
        }

四,Linq常用扩展方法1

LINQ中提供了大量类似Where的扩展方法,简化数据处理。大部分都在System.Linq命名空间中。

1. 创建一个Employee类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Linq2
{
    //准备初始数据,全部代码见备注
    class Employee
    {
        public long ld { 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
            $"ld={ld},Name={Name},Age={Age},Gender={Gender},Salary={Salary}";
        }
    }
}

using System.Collections.Generic;
using System.Linq;

 static void Main(string[] args)
        {
            List<Employee> list = new List<Employee>();
            list.Add(new Employee { ld = 1, Name = "jerry", Age = 28, Gender = true, Salary = 5000 });
            list.Add(new Employee { ld = 2, Name = "jim", Age = 33, Gender = true, Salary = 3000 });
            list.Add(new Employee { ld = 3, Name = "lily", Age = 35, Gender = false, Salary = 9000 });
            list.Add(new Employee { ld = 4, Name = "lucy", Age = 16, Gender = false, Salary = 2000 });
            list.Add(new Employee { ld = 5, Name = "kimi", Age = 25, Gender = true, Salary = 1000 });
            list.Add(new Employee { ld = 6, Name = "nancy", Age = 35, Gender = false, Salary = 8000 });
            list.Add(new Employee { ld = 7, Name = "zack", Age = 35, Gender = true, Salary = 8500 });
            list.Add(new Employee { ld = 8, Name = "jack", Age = 33, Gender = true, Salary = 8000 });
            //Where方法
            IEnumerable<Employee> items1 = list.Where(e => e.Age > 30);
            //
            foreach (Employee e in items1)
            {
                Console.WriteLine(e);
            }
            //数据总条数量
            list.Count();
            Console.WriteLine(list.Conunt(e=>e.Age>20));
            //判断是否有一条满足
            Console.WriteLine(list.Any(e=>e.Salary>3000));

        }

五,LinQ常见扩展方法2

获取一条数据(是否带参数的两种写法):
选择合适的方法,“防御性编程”

1.Single:有且只有一条满足要求的数据

 //打印整条数据(有且只有一条满足)
            //IEnumerable<Employee> items2 = list.Where(e => e.Name == "jerry");
            //Employee el = items1.Single();
            //Console.WriteLine(el);

            //Employee e2 = list.Where(e => e.Name == "jerry").Single();
            Employee e2 = list.Single(e => e.Name == "lily");
            Console.Write(e2);

2.SingleOrDefault :最多只有一条满足要求的数据

    //最多只有一条满足数据的要求SingleOrDefault
            Employee e2 = list.SingleOrDefault(e => e.Name == "lily");
            Console.WriteLine(e2);
            int[] nums = new int[] { 3, 5, 8 };
            int i = nums.SingleOrDefault(i => i > 7);
            Console.WriteLine(i);

3.First :至少有一条,返回第一条

 // 至少有一条,返回第一条;
            Employee e2 = list.First(e => e.Age > 20);
            Console.WriteLine(e2);

4.FirstOrDefault :返回第一条或者默认值

在这里插入代码片

5.排序

Order()对数据正序排序;

  //正序排序
            IEnumerable<Employee> items = list.OrderBy(e => e.Age);
            foreach(Employee e in items)
            {
                Console.WriteLine(e);
            }

OrderByDescending()倒序排序;

对于简单类型排序,也许不用lambda表达式。


            //倒序排序
            IEnumerable<Employee> items = list.OrderByDescending(e => e.Age);
            foreach (Employee e in items)
            {
                Console.WriteLine(e);
            }
  var nums = new int[] { 3, 4, 5, 2, 6, 24, 23 };
            IEnumerable<int> nums2 = nums.OrderByDescending(i => i );
            foreach(var i in nums2)

            {
                Console.WriteLine(i);   
            }
               

特殊案例:按照最后一个字符排序;

 //最后一个字母从大到小
            var items = list.OrderByDescending(e => e.Name[e.Name.Length - 1]);
            foreach(Employee e in items)
            {
                Console.WriteLine(e);
            }

用Guid或者随机数进行随机排序。

   //随机排序
            Random rand = new Random();
            //var item = list.OrderByDescending(e => Guid.NewGuid());
            var item = list.OrderByDescending(e => rand.Next())); ;
            foreach (var i in item)

            {
                Console.WriteLine(i);
            }

多排序

//多排序
            var items = list.OrderBy(e => e.Age).ThenBy(e=>e.Salary);
            foreach (Employee e in items)
            {
                Console.WriteLine(e);
            }

6.限制结果集,获取部分数据

Skip(n)跳过n条数据,Take(n)获取n条数据。

  //跳过数据取数据
            var items = list.Skip(3).Take(2);
            foreach (Employee e in items)
            {
                Console.WriteLine(e);
            }
          //链式编程
            var item = list.Where(e => e.Age > 30).OrderBy(e => e.Age).Skip(1).Take(2);
            foreach (Employee e in item)
            {
                Console.WriteLine(e);
            }

六,Linq常见扩展方法三

聚合函数:

Max()、Min ()、Average ()、Sum ()、Count ()。
LINQ中所有的扩展方法几乎都是针对lEnumerable接口的,而几乎所有能返回集合的都返回IEnumerable,所以是可以把几乎所有方法“链式使用”的。
list.Where(e =>e.Age > 30).Min(e=>e.Salary)

    //int a = list.Max(e => e.Age);
            //Console.WriteLine(a);

            //int a = list.Where(e => e.ld > 6).Max(e=>e.Salary);
            //Console.WriteLine(a);
            string s = list.Max(e => e.Name);//字符串大小比较算法
            Console.WriteLine(s);
            //平均值
            double a = list.Where(e => e.Age >= 30).Average(e => e.Salary);
            Console.WriteLine(a);

分组:

GroupBy()方法参数是分组条件表达式,返回值为IGrouping<TKey, TSource>类型的泛型IEnumerable,也就是每一组以一个
lGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口,IGrouping中Key属性表示这一组的分组数据的值。

 //分组
            IEnumerable<IGrouping<int, Employee>> items = list.GroupBy(e => e.Age);
            foreach(IGrouping<int,Employee>g in items)
            {
                Console.WriteLine(g.Key);
                Console.WriteLine("最大工资:" + g.Max(e => e.Salary));
                foreach(Employee e in g)
                {
                    Console.WriteLine(e);
                }
                Console.WriteLine("***********");
            }

七,Linq常用扩展方法四

投影:

把集合中的每一项转换为另外一种类型。lEnumerable ages = list.Select(e =>e.Age);
IEnumerable names=
list.Select(e=>e.Gender?“男”:“女”);var dogs = list.Select(p=>new
Dog{NickName=e.Name,Age=e.Age});

    //投影
            //IEnumerable<int> items = list.Select(e => e.Age);
            //foreach(int i in items)
            //{
            //    Console.WriteLine(i);
            //}

            //IEnumerable<string> items =list.Where(e=>e.Age>30).Select(e => e.Name);
            //foreach (string i in items)
            //{
            //    Console.WriteLine(i);
            //}

            //IEnumerable<string> items = list.Where(e => e.Salary > 5000).Select
            //    (e => e.Gender ? "男" : "女");
            //foreach(string i in items)
            //{
            //    Console.WriteLine(i);
            //}
            //IEnumerable<Dog> items = list.Select(e => new Dog { NickName = e.Name, Age = e.Salary });
            //foreach (Dog i in items)
            //{
            //    Console.WriteLine($"{i.NickName},{i.Age}");
            //}

匿名类型:

var p = new {Name=“tom”,ld=1;var p1= new {name,ld=1,p.Agel;通过反编译看匿名类型原理。var的高光时刻!

   //匿名类型
            Dog dl = new Dog { NickName = "aa" };
            var obj1 = new { Name = "ddd", Salary = 3, AAA = "aa", bb = 2 };
            Console.WriteLine(obj1.AAA);

投影与匿名类型:


            //投影与匿名类型:
            //var items=
            //list.Select(e => new
            //{
            //    XingMing = e.Name,
            //    NianLing = e.Age,
            //    xingbie = e.Gender ? "男" : "女"
            //});
            //foreach(var ss in items)
            //{
            //    Console.WriteLine(ss.NianLing+ss.xingbie); 
            //}
            IEnumerable<IGrouping<int, Employee>> item = list.GroupBy(e => e.Age);
            var item1 = list.GroupBy(e => e.Age).Select(g => new
            {
                NianLing = g.Key,
                MaxS = g.Max(e => e.Salary),
                RenShu = g.Count()
            })
                ;
            foreach(var i in item1)
            {
                Console.WriteLine(i.NianLing + "," + i.MaxS + "," + i.RenShu); 
            }
              list.ToLookup(e => e.Name);

八,Linq链式调用

集合转换:

有一些地方需要数组类型或者List类型的变量,我们可以用ToArray()方法和ToList()分别把lEnumerable转换为数组类型和List类型。

  //集合转换:
            IEnumerable<Employee> itmes = list.Where(e => e.Salary > 6000);
            List<Employee> list1 = itmes.ToList();
            Employee[] array2 = itmes.ToArray();

链式调用

Where、Select、OrderBy、GroupBy、Take、Skip等返回值都是
lEnumerable类型,所以可以链式调用。例子:“获取ld>2的数据,然后按照Age分组,并且把分组按照Age排序,然后取出前3条,最后再投影取得年龄、人数、平均工资”

   //链式调用

            //GroupBy:[(key,e)]
            //IEnumerable<IGrouping<int,Employee>>
            var items = list.Where(e => e.ld > 2).GroupBy(e => e.Age).OrderBy(g => g.Key)
                 .Take(3)
                 //g=IGrouping<int,Employee>
                 .Select(g => new
                 {
                     NL = g.Key,
                     Rs = g.Count(),
                     PjGz = g.Average(e => e.Salary)
                 });
            foreach (var i in items)

            {
                Console.WriteLine(i.NL+","+i.Rs+","+i.PjGz);
            }

九,Linq语法

查询语法

使用Where、OrderBy、Select等扩展方法进行数据查询的写法叫做“LINQ方法语法”。还有一种“查询语法”…的写法… …

//语法
            //            var items = list.Where(e => e.Salary > 3000).OrderBy(e => e.Age)
            //.Select(e => new { e.Age, e. Name, XB = e.Gender ? "男" : "女" });

            var items = from e in list
                        where e.Salary > 5000
                        select new
                        {
                            e.Age,
                            e.Name,
                            XB = e.Gender ? "男" : "女"
                        };
            //            foreach(var e in items)
            //            {
            //                Console.WriteLine(e);
            //            }

十,Linq解决简单问题

计算字符串用逗号分隔的数据的平均值

//计算字符串用逗号分隔的平均值
            string s = "55,66,11,44,15,46,65";
            //方法一
            //string[] str = s.Split(',');
            //IEnumerable<int> num = str.Select(e => Convert.ToInt32(e));
            //double avg = num.Average();
            //Console.WriteLine(avg);

            //方法二
            double avg = s.Split(',').Select(e => Convert.ToInt32(e))
                .Average();
            Console.WriteLine(avg);

统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率。

 string s = "hello wordyy,asf, FASDFASGGASHHHA";
           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);
              foreach(var item in items)
            {
                Console.WriteLine(item);
            }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值