C#之LINQ大全
最编程
2024-08-10 16:57:28
...
一、手写Linq Where方法
1.Linq前置知识:枚举器与迭代器、泛型、委托、Lambda表达式、yeild关键字、匿名方法、拓展方法、var关键字
- Linq的方法都是 IEnumerable<T>的扩展方法>>只要实现了 IEnumerable<T>的都可以使用Linq里面提供的扩展方法
比如:数组、List、Dictionary、Set.....
using System;
using System.Collections.Generic;
using System.Linq;
using ConsoleApp1;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int[] nums = new int[] { 7, 8, 9, 10, 11, 33, 456 };
//默认调用Linq Where(扩展方法)
IEnumerable<int> result = nums.Where(a => a > 10);
foreach (var i in result)
{
Console.WriteLine(i);
}
//调用第一个自定义Where方法
IEnumerable<int> GetNumsFromMyWhere1 = MyWhere1(nums, a => a > 10);
/*
*var进行类型推断等同上 IEnumerable<int>
var GetNumsFromMyWhere1 = MyWhere1(nums, a => a > 10);
*/
foreach (var i in GetNumsFromMyWhere1)
{
Console.WriteLine(i);
}
//调用第二个自定义Where方法
IEnumerable<int> GetNumsFromMyWhere2 = MyWhere2(nums, a => a > 10);
/*
var GetNumsFromMyWhere2 = MyWhere2(nums, a => a > 10);
*/
foreach (var i in GetNumsFromMyWhere2)
{
Console.WriteLine(i);
}
}
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))
{
result.Add(item);
}
}
return result;
}
static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
{
List<int> result = new List<int>();
foreach (var item in items)
{
if (f(item))
{
yield return item; //动态返回:处理一次返回一次,相对第一种效率更改
}
}
}
}
}
二、LINQ基础语法合集
1.常用函数:Where、Count、Any、Single、SingleOrDefault、First、OrderBy、Skip、Take、Max、Min、Select、Groupby
2.集合转换:IEnumerable<T>转换成列表或数组
3.【Linq方法语法】与【类SQL的查询语法】区别
4.常用函数的链式操作
using System;
using System.Collections.Generic;
using System.Linq;
using ConsoleApp1;
namespace ConsoleApp1
{
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, Salary = 5000 });
List.Add(new Employee { id = 2, Name = "jim", Age = 33, Gender = true, Salary = 3000 });
List.Add(new Employee { id = 3, Name = "lily", Age = 35, Gender = false, Salary = 9000 });
List.Add(new Employee { id = 4, Name = "lucy", Age = 16, Gender = false, Salary = 2000 });
List.Add(new Employee { id = 5, Name = "kimi", Age = 25, Gender = true, Salary = 1000 });
List.Add(new Employee { id = 6, Name = "nancy", Age = 35, Gender = false, Salary = 8000 });
List.Add(new Employee { id = 7, Name = "zack", Age = 35, Gender = true, Salary = 8500 });
List.Add(new Employee { id = 8, Name = "jack", Age = 33, Gender = true, Salary = 8000 });
//Where
UseWhere(List);
//Count
UseCount(List);
//Any,至少有一条数据则返回True
UseAny(List);
//Single:只接收一条数据,0条或者多条直接语法上报错
UseSingle(List);
//SingleOrDefault:只接收一条数据,多条报错,0条返回默认值:null(因为Employee是引用类型,如果是int类型则返回默认值0);
UseSingleOrDefault(List);
//First:返回数据一条都没有语法上报错,有1条或更多返回第一条 类似Single
//FirstOrDefault:类似SingleOrDefault
//OrderBy:按照指定字段进行正序排序>>按照一个字段或者按照多个字段语法差异较大,需要注意
UseOrderBy(List);
//OrderByDescending:按照指定字段进行倒序排序
//Skip(n)跳过第N条数据,Take(n)获取第N条数据
UseSkipAndTake(List);
//综合练习1:链式操作
Console.WriteLine("This 链式操作");
IEnumerable<Employee> items = List.Where(e => e.Age > 30).
OrderBy(e => e.Age).Skip(1).Take(2);
foreach (var item in items)
{
Console.WriteLine(item);
}
Console.WriteLine("--------");
//Max:获取最大值
UseMax(List);
//Min、Average、Count、Sum 同Max类似
//GroupBy():参数是分组条件表达式,返回值为IGrouping<Tkey,TSource>类型的泛型IEnumberable
//也就是每一组以一个IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口
//Key属性表示这一组的分组数据的值。例子:按年龄分组,获取每组人数、最高工资。可以用var简化编程
UseGroupBy(List);
//Select:投影操作>>把集合中的每一项转换成另外一种类型。Select与Groupby与匿名函数、max、min结合使用
UseSelect(List);
//集合转换:IEnumerable<T>转换成列表或数组
IEnumerable<Employee> toListOrArray = List.Where(e => e.Salary > 6000);
List<Employee> fromIEnumerableList = toListOrArray.ToList();
Employee[] fromIEnumerableArray = toListOrArray.ToArray();
//综合练习2:链式操作 需求:获取id>2的数据,然后按照Age分组,并且把分组按照Age排序,然后取前三条,最后再投影取得年龄、人数、平均工资
var practice2 = List.Where(e => e.id > 2)
.GroupBy(e => e.Age)
.OrderBy(e => e.Key).Take(3)
.Select(e => new
{
Age = e.Key,
CountPeople = e.Count(),
AvgS = e.Average(e => e.Salary)
});
foreach (var item in practice2)
Console.WriteLine(item);
//一种过时的语法:以上叫“Linq方法语法”,以下过时的语法称为查询语法>>类似SQL语法,最终编译结果与两种形式一致。
var LikeSql = from e in List
where e.Salary > 5000
select new
{
e.Age,
e.Name,
Gender = e.Gender?"男":"女"
};
foreach (var item in practice2)
Console.WriteLine(item);
}
public static void UseWhere(List<Employee> List)
{
IEnumerable<Employee> items1 = List.Where(e => e.Age > 30);
Console.WriteLine(items1);
foreach (var item in items1)
Console.WriteLine(item);
}
public static void UseCount(List<Employee> List)
{
Console.WriteLine(List.Count());
Console.WriteLine(List.Count(e => e.Age > 20));
Console.WriteLine(List.Count(e => e.Age > 20 && e.Salary > 8000));
}
public static void UseAny(List<Employee> List)
{
Console.WriteLine(List.Any());
Console.WriteLine(List.Any(e => e.Salary > 300000));
Console.WriteLine(List.Any(e => e.Salary < 8000));
}
public static void UseSingle(List<Employee> List)
{
//Employee e1 = List.Single(); 报错
//Console.WriteLine(e1);
Employee e2 = List.Where(e => e.Name == "jerry").Single();
Console.WriteLine(e2);
Employee e3 = List.Single(e => e.Name == "jack"); //Single可以传入委托,相比较于使用where语法更简洁
Console.WriteLine(e3);
}
public static void UseSingleOrDefault(List<Employee> List)
{
//Employee e1 = List.Single(); 报错
//Console.WriteLine(e1);
Employee e3 = List.SingleOrDefault(e => e.Name == "jack");
Console.WriteLine(e3);
Employee e4 = List.SingleOrDefault(e => e.Name == "ssss");
Console.WriteLine(e4); // 返回null;
Console.WriteLine(e4==null); //验证是否是null
}
public static void UseOrderBy(List<Employee> List)
{
IEnumerable<Employee> items1 = List.OrderBy(e => e.Age); //根据年龄排序
IEnumerable<Employee> items2 = List.OrderBy(e => e.Salary); //根据工资排序
var items3 = List.OrderBy(e => e.Age).ThenByDescending(e => e.Salary); //优先按照年龄正序,次优先按照工资倒叙
Console.WriteLine("This UseOrderBy");
foreach (Employee item in items1)
Console.WriteLine(item);
Console.WriteLine("--------");
foreach (Employee item in items2)
Console.WriteLine(item);
Console.WriteLine("--------");
foreach (var item in items3)
Console.WriteLine(item);
Console.WriteLine("--------");
}
public static void UseSkipAndTake(List<Employee> list)
{
IEnumerable<Employee> items1 = list.Skip(2); //从第三条数据开始,跳过1.2条数据
IEnumerable<Employee> items2 = list.Take(2); //从头开始获取2条数据
IEnumerable<Employee> items3 = list.Skip(1).Take(3); //从第2条数据开始开始获取3条数据,跳过第一条数据
Console.WriteLine("This UseSkipAndTake");
foreach (Employee item in items1)
Console.WriteLine(item);
Console.WriteLine("--------");
foreach (Employee item in items2)
Console.WriteLine(item);
Console.WriteLine("--------");
foreach (Employee item in items3)
Console.WriteLine(item);
Console.WriteLine("--------");
}
public static void UseMax(List<Employee> list)
{
Console.WriteLine("This Max");
int a = list.Max(a => a.Age); //年龄最大值 返回值是int类型
int b = list.Where(a => a.id > 6).Max(a => a.Salary); //id大于6中工资最大值 返回值是int类型
string name = list.Max(a => a.Name); //返回值是泛型,此时就是string类型,实现方式可以自行搜索:字符串比较大小算法
Console.WriteLine($"年龄最大的是{a}");
Console.WriteLine($"id大于6中工资最大是{b}");
Console.WriteLine($"名字使用Max函数结果是:{name}");
Console.WriteLine("--------");
}
public static void UseGroupBy(List<Employee> list)
{
Console.WriteLine("This UseGroupBy");
//对应的sql:select age,max(Salary), from t group by age;
IEnumerable<IGrouping<int, Employee>> items = list.GroupBy(e => e.Age);
foreach (IGrouping<int, Employee> item1 in items)
{
Console.WriteLine(item1.Key);
Console.WriteLine($"最大工资{item1.Max(e=>e.Salary)}");
foreach (Employee item2 in item1)
{
Console.WriteLine(item2);
}
}
Console.WriteLine("--------");
}
public static void UseSelect(List<Employee> list)
{
Console.WriteLine("This Select");
IEnumerable<int> Ages = list.Select(e => e.Age); //只取出年龄信息
foreach (var age in Ages)
{
Console.WriteLine(age);
}
IEnumerable<String> Names = list.Select(e => e.Name); //只取出名字信息
foreach (var name in Names)
{
Console.WriteLine(name);
}
IEnumerable<String> NamesAndAges = list.Where(e=>e.Age>30).Select(e => e.Name+","+e.Age); //过滤后取出名字加年龄
foreach (var item in NamesAndAges)
{
Console.WriteLine(item);
}
//Select与Groupby与匿名函数、max、min结合使用
var items = list.GroupBy(e => e.Age).
Select(e => new
{
Age = e.Key,
MaxS = e.Max(e => e.Salary),
MinS = e.Min(e => e.Salary),
CountPeople = e.Count()
}) ;
foreach (var item in items)
Console.WriteLine(item);
Console.WriteLine("--------");
}
}
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}";
}
}
}
三、练习
P1:根据字符串求平均值
using System;
using System.Collections.Generic;
using System.Linq;
using ConsoleApp1;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
//需求 :求str1的平均分
string str1 = "53,33,55,888,9";
string[] str2 = str1.Split(',');
//方法一:
int[] num1 = Array.ConvertAll(str2, e => int.Parse(e));
double avgSorce1 = num1.Average(e => e);
Console.WriteLine(avgSorce1);
//方法二:用投影将string类型的数组转成int类型的IEnumerable
IEnumerable<int> num2 = str2.Select(e => Convert.ToInt32(e));
double avgSorce2 = num2.Average(e => e);
Console.WriteLine(avgSorce2);
//方法三:将方法二进行链式操作
double avgSorce3 = str2.Select(e => Convert.ToInt32(e)).Average(e=>e);
Console.WriteLine(avgSorce3);
}
}
}
P2:统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率;
using System;
using System.Collections.Generic;
using System.Linq;
using ConsoleApp1;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string str1 = "hello World,Hahah,heiheihei";
var res =
str1.Where(e=>char.IsLetter(e)).
Select(e => char.ToLower(e) ).
GroupBy(e => e).
Select(e => new { e.Key, count = e.Count() }).
Where(e => e.count > 2).
OrderByDescending(e=>e.count);
foreach (var item in res)
{
Console.WriteLine(item);
}
}
}
}
上一篇: ASP.NET MVC 全方位指南
下一篇: 理解Linq的延迟执行基础概念