文章目录
Where方法
每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。
Where参数是一个lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象。参数的名字不一定非要叫e,不过一般lambda表达式中的变量名长度都不长。
static void Main(string[] args)
{
List<Employee> list = new List<Employee>();
list.Add(new Employee { Id = 1, Name = "张三", Age = 30, Gender = false, Salary = 3500});
list.Add(new Employee { Id = 2, Name = "李四", Age = 48, Gender = false, Salary = 6000});
list.Add(new Employee { Id = 3, Name = "王五", Age = 16, Gender = true, Salary = 2800});
list.Add(new Employee { Id = 4, Name = "赵六", Age = 16, Gender = false, Salary = 4100});
list.Add(new Employee { Id = 5, Name = "田七", Age = 33, Gender = true, Salary = 3000});
IEnumerable<Employee> items = list.Where(e => e.Age > 40);
foreach (var item in items)
{
Console.WriteLine(item);
}
}
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}";
}
}
Count()方法
获取数据条数
int count1 = list.Count(e => e.Salary > 5000 || e.Age < 30);
int count2 = list.Where(e => e.Salary > 5000 || e.Age < 30).Count();
Any()方法
是否至少有一条数据
bool b1 = list.Any(e => e.Salary > 8000);
bool b2 = list.Where(e => e.Salary > 8000).Any();
比Count()实现效率高。
获取一条数据(是否带参数的两种写法)
Single
有且只有一条满足要求的数据,如果都不满足或者满足多条数据则抛出异常。
Employee e1= list.Where(e => e.Id == 4).Single();
Employee e2= list.Single(e => e.Id == 4);
Console.WriteLine(e2);
SingleOrDefault
最多只有一条满足要求的数据,如果都不满足返回默认值,如果满足多条则抛出异常。
Employee e2 = list.SingleOrDefault(e => e.Id == 4);
Employee e3 = list.SingleOrDefault(e => e.Id == 10);
Console.WriteLine(e3 == null);
First
至少有一条,返回第一条,如果都不满足抛出异常
Employee e4 = list.First(e => e.Age > 30);
Employee e5 = list.First(e => e.Age > 100);
FirstOrDefault
返回第一条或者默认值
Employee e6 = list.FirstOrDefault(e => e.Age > 100);
Console.WriteLine(e6 == null);
排序
Order()
对数据正序排序;
list.OrderBy(e => e.Age);
OrderByDescending()
倒序排序;
IEnumerable<Employee> list2= list.OrderByDescending(e => e.Age);
用Guid或者随机数进行随机排序:
IEnumerable<Employee> list2= list.OrderBy(e => Guid.NewGuid());
Random random = new Random();
IEnumerable<Employee> list2= list.OrderBy(e => random.Next());
按照最后一个字符排序:
IEnumerable<Employee> list2= list.OrderBy(e => e.Name[e.Name.Length - 1]);
多规则排序
可以在Order()
、OrderByDescending()
后继续写ThenBy ()
、ThenByDescending()
。
优先按照Age排序,如果Age相同再按照Salary排序
list.OrderBy(e => e.Age).ThenByDescending(e => e.Salary)
// 千万不要写成
// list.OrderBy(e => e.Age).OrderByDescending(e => e.Salary)
限制结果集,获取部分数据
Skip(n)
跳过n条数据,Take(n)
获取n条数据。
获取从第2条开始获取3条数据:
var orderedItems1 = list.Skip(2).Take(3);
Skip()
、Take()
也可以单独使用。
var orderedItems1 = list.Skip(2);
var orderedItems2 = list.Take(3);
Tips:LINQ中所有的扩展方法几乎都是针对IEnumerable接口的,而几乎所有能返回集合的都返回IEnumerable
,所以是可以把几乎所有方法“ 链式使用 ”的。
聚合函数
Max()
、Min()
、Average()
、Sum()
、Count()
。
//最大年龄
int a = list.Max(e => e.Age);
//最小年龄
int a = list.Min(e => e.Age);
//年龄大于等于30岁的平均年龄
double b = list.Where(e => e.Age >= 30).Average(e => e.Age);
//集合中所有年龄的和
int sum = list.Sum(e => e.Age);
//集合个数
int count = list.Count();
分组
GroupBy()
方法参数是分组条件表达式,返回值为IGrouping<TKey, TSource>
类型的泛型IEnumerable
,也就是每一组以一个IGrouping
对象的形式返回。IGrouping
是一个继承自IEnumerable
的接口,IGrouping
中Key
属性表示这一组的分组数据的值。
IEnumerable<IGrouping<int, Employee>> g = list.GroupBy(x => x.Age);
foreach (IGrouping<int, Employee> item in g)
{
Console.WriteLine(item.Key);
foreach (var e in item)
{
Console.WriteLine(e);
}
}
投影
投影是把集合中的每一项转换为另外一种类型。
IEnumerable<int> ages = list.Select(e => e.Age);
IEnumerable<string> names = list.Select(e=>e.Gender?"男":"女");
var dogs = list.Select(p=>new Dog{NickName=e.Name,Age=e.Age});
匿名类型
var p = new {Name="tom", Id=1};
//属性名称一样时,可以省略
var p1 = new {name, Id=1, p.Age};
var select = list.Select(e => new { NianLing = e.Age, XingBie = e.Gender ? "男" : "女" });
foreach (var item in select)
{
Console.WriteLine(item.NianLing + "," + item.XingBie);
}
var items = list.GroupBy(e => e.Gender)
.Select(g=>new { Gender=g.Key,Count=g.Count(),AvgSalary= g.Average(e => e.Salary),MinAge= g.Min(e => e.Age)});
通过反编译软件查看dll文件,编译器最后也是生成了具体的类,只不过这个类名是编译器自动生成的。
集合转换
有一些地方需要数组类型或者List类型的变量,可以用ToArray()
方法和ToList()
分别把IEnumerable<T>
转换为数组类型和List<T>
类型。
查询语法
使用Where、OrderBy、Select等 扩展方法进行数据查询的写法叫做 “LINQ方法语法”。还有一种“查询语法”的写法。
var items2 = from e in list
where e.Salary > 3000
orderby e.Age
select new { e.Name, e.Age, Gender = e.Gender ? "男" : "女" };
//等同于以下写法
var items3 = list.Where(e => e.Salary > 3000).OrderBy(e => e.Age).
Select(e => new { e.Name, e.Age, Gender = e.Gender ? "男" : "女" });
Tips:日常开发推荐方法语法。
统计一个字符串中每个字母出现的频率(忽略大小写),然后按照从高到低的顺序输出出现频率高于2次的单词和其出现的频率:
var items = s.Where(c => char.IsLetter(c))//过滤非字母
.Select(c => char.ToLower(c))//大写字母转换为小写
.GroupBy(c => c)//根据字母进行分组
.Where(g=>g.Count()>2)//过滤掉出现次数<=2
.OrderByDescending(g => g.Count())//按次数排序
.Select(g=>new { Char=g.Key,Count=g.Count()});
委托
1、委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法。
static void Main(string[] args)
{
D1 d = F1;
d();
}
static void F1()
{
Console.WriteLine("hello");
}
delegate void D1();
匿名方法:
static void Main(string[] args)
{
Action a = delegate() {
Console.WriteLine("hello world");
};
a();
}
static void Main(string[] args)
{
Action a = delegate() {
Console.WriteLine("hello world");
};
Func<int, int, int> func = delegate (int a, int b)
{
return a + b;
};
Console.WriteLine(func(1, 2));
}
Lambda表达式
Func<int, int, string> f1 = (i1,i2) =>{
return $"{i1}+{i2}={i1 + i2}";
};
- 可以省略参数数据类型,因为编译能根据委托类型推断出参数的类型,用=>引出来方法体。
- 如果委托没有返回值,且方法体只有一行代码,可省略 {}
- 如果=>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的{}以及return。
- 如果只有一个参数,参数的()可以省略。
2、.NET 中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。
static void Main(string[] args)
{
Action a = F1;
a();
}
static void F1()
{
Console.WriteLine("hello");
}
static void Main(string[] args)
{
Func<int, int, int> func = F2;
int sum = func(2, 5);
Console.WriteLine(sum);
}
static int F2(int a, int b)
{
return a + b;
}
LINQ
筛选出数组中大于3的数字:
IEnumerable<int> ints = [ 2,3,4,5,5];
IEnumerable<int> result = ints.Where(a => a > 3);
通过编写扩展方法MyWhere来模拟Where的实现:
static void Main(string[] args)
{
IEnumerable<int> ints = [ 2,3,4,5,5];
//IEnumerable<int> result = ints.Where(a => a > 3);
IEnumerable<int> result = MyWhere(ints, a => a > 3);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
static IEnumerable<int> MyWhere(IEnumerable<int> ints, Func<int, bool> func)
{
List<int> result = new List<int>();
foreach (var item in ints)
{
if(func(item)) result.Add(item);
}
return result;
}
yield return
通过yield return
来让MyWhere“流水线”处理:
static void Main(string[] args)
{
IEnumerable<int> ints = [ 2,3,4,5,5];
//IEnumerable<int> result = ints.Where(a => a > 3);
IEnumerable<int> result = MyWhere(ints, a => a > 3);
foreach (var item in result)
{
Console.WriteLine(item);
}
}
static IEnumerable<int> MyWhere(IEnumerable<int> ints, Func<int, bool> func)
{
List<int> result = new List<int>();
foreach (var item in ints)
{
if(func(item)) yield return item;
}
}