Linq
一.初识Linq
Linq中提供了很多集合的扩展方法,配合Lambda能简化数据处理.
比如我们需要获取数组中大于10的数
using System.Linq;
int[] nums = new int[]{3,88,99,55,77,66,15,7};
IEnumerable<int> items = nums.Where(i => i > 10);
Where原理其实如下:
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;
}
我们可以结合yield,变成流水化的处理
static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
{
foreach (int i in items)
{
if (f(i) == true)
{
yield return i;
}
}
}
我们顺带提一下var这个声明类型,我们可以使用var让编译器的"类型推断"来简化类型的声明.在Linq中常用,C#的var和JavaScript的var不一样,仍然是强类型的.会根据右边的值推断什么类型.
C#中的弱类型是dynamic
二.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}";
}
}
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 });
}
1.Where方法
每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中.
Where参数是一个Lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象,参数的名字不一定非要叫e,不过一般Lambda表达式中的变量名长度都不长
IEnumerable<Employee> items1 = list.Where(e => e.Age > 30);
foreach (Employee e in items1)
{
Console.WriteLine(e);
}
2.Count()方法
获取数据条数
Console.WriteLine(list.Count());
Console.WriteLine(list.Count(e => e.Age>20));
Console.WriteLine(list.Count(e => e.Age > 20 && e.Salary > 8000));
3.Any()方法
是否至少有一条数据
Console.WriteLine(list.Any(e => e.Salary > 300000));
Console.WriteLine(list.Any(e => e.Salary > 5000));
4.获取一条数据方法
Single():有且只有一条满足要求的数据
Employee e1 = list.Where(e => e.Name == "jerry").Single();
Console.WriteLine(e1);
SingleOrDefault():最多只有一条满足要求的数据
Employee e2 = list.SingleOrDefault(e => e.Name == "jim");
Console.WriteLine(e2);
First():至少有一条,返回第一条
Employee e3 = list.First(e => e.Age > 30);
Console.WriteLine(e3);
FirstOrDefault():返回第一条或者默认值
Employee e4 = list.FirstOrDefault(e => e.Age > 30);
Console.WriteLine(e4);
5.排序方法
Order(): 对数据正序排序
IOrderedEnumerable<Employee> orderedEnumerable1 = list.OrderBy(e.Name[e.Name.Length - 1]);
foreach (Employee e in orderedEnumerable1)
{
Console.WriteLine(e);
}
OrderByDescending(): 对数据倒序排序
IOrderedEnumerable<Employee> orderedEnumerable2 = list.OrderByDescending(e => e.Age).ThenBy(e => e.Salary);//先按年龄再按工资排序
foreach (Employee e in orderedEnumerable2)
{
Console.WriteLine(e);
}
6.限制结果集,获取部分数据
Skip(n):跳过n条数据
Take(n):获取n条数据
IEnumerable<Employee> enumerable3 = list.Skip(3).Take(2);
foreach (Employee e in enumerable3)
{
Console.WriteLine(e);
}
7.聚合函数
Max(),Min(),Average(),Sum(),Count()
Linq中所有的扩展方法几乎都是针对
8.分组
GroupBy()方法参数是分组条件表达式,返回值为IGrouping<TKey,TSource>类型的泛型IEnumerable,也就是每一组以一个IGrouping对象的形式返回.IGrouping是一个继承自IEnumerable的接口,IGrouping中Key属性表示这一组的分组数据的值.
例子:根据年龄分组,获取每组人数,最高工资,平均工资
var items = list.GroupBy(e => e.Age);
foreach (IGrouping<int, Employee> g in items)
{
Console.WriteLine(g.Key);
foreach (Employee e in g)
{
Console.WriteLine(e);
}
Console.WriteLine("**********");
}
9.投影
把集合中的每一项转换为另外一种类型.
var items2 = list.GroupBy(e => e.Age).Select(g => new
{NianLing = g.Key, MaxS = g.Max(e => e.Salary), MinS = g.Min(e => e.Salary), RenShu = g.Count()});
foreach (var e in items2)
{
Console.WriteLine(e.NianLing + ","+e.MaxS+","+e.MinS+","+e.RenShu);
}
10.集合转换
有一些地方需要数组类型或者List类型的变量,我们可以用ToArry()方法和ToList()分别把IEnumerable转换为数组类型和List类型
var items3 = list.Where(e => e.Salary > 6000);
List<Employee> list1 = items3.ToList();
Employee[] array = items3.ToArray();
11.链式调用
Where,Select,OrderBy,GroupBy,Take,Skip,等返回值都是IEnumerable类型,所以可以链式调用.
var items4 = list.Where(e => e.Id > 2)
.GroupBy(e => e.Age)
.OrderBy(g => g.Key)
.Take(3)
.Select(g => new {NL = g.Key, RS = g.Count(), PJ = g.Average(e =>e.Salary)});
foreach (var i in items4)
{
Console.WriteLine(i.NL+","+i.RS+","+i.PJ);
}