C#从零开始学习笔记---第十二天
ok啊,回顾前几次的内容,我们分别记录了数组,集合,哈希表,类以及类的一些方法的调用。按理来说今天应该继续类的内容,但我思来想去觉得既然都到这儿了,那我们插入一点方法的内容以及跟数组结合的一些操作。把这里说完我们再继续类的内容,不过这期不会说纯记录这些,虽然内容说多不多说少不少的,但也不会说很跳脱,大家放心食用。
1. 高阶函数和回调函数
我们先来说说高阶函数。高阶函数是指可以接收其他函数作为参数,或者将函数作为返回值的函数。说白了,高阶函数的参数也是一个函数。那什么是回调函数呢?回调函数是通过将函数作为参数传递给另一个函数,在特定事件活条件触发时被调用的函数。或者说,回调函数就是我们高阶函数里的那个参数函数。他们两者经常结合使用,这也是为什么我把他们两个放在一起的原因。
事先声明一下,因为我们肯定要举例说明,但为了让这期的内容跟我们之前所需的内容结合在一块,我们就用编译器内置的一些数组的方法来进行举例,顺便也带着大家学习一下这些方法。
1.1 Array.Find()方法
工作原理: Array.Find()会循环该数组,并且每次循环调用传递的方法,并且将当前数组,通过参数的形式传递到方法中,如果方法返回了true,则Find直接返回当前这个参数
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//找到第一个偶数
Console.WriteLine(Array.Find(arr1, FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
可以看到,这里我们现在主函数里定义一个数组作为我们要操作的对象。然后我们在外面定义了一个静态的方法,需要我们传入一个参数,然后函数体的内容就是判断传入的这个参数是奇数还是偶数。然后看我们的输出语句,就用到了 Array.Find()方法。在上面我们介绍了它的工作原理,这里我们说一下他的两个参数。第一个参数arr1就是我们定义的那个数组,然后第二个参数就是FindEven就是我们自定义的那个判断一个数是否是偶数的函数,因为它的工作原理是方法返回了true,Find就直接返回当前的这个参数。所以在找到第一个数之后,整个过程就结束了。我们可以看一下结果:

结果就是2。然后我们来思考一下在这个函数调用的过程中,那个函数是高阶函数,那个函数是回调函数。我想应该是一目了然。没错, Array.Find()就是高阶函数,FindEven()就是回调函数。如果还没有理解没关系,我们还有下面的例子。
1.2 Array.FindLast()
工作原理:Array.FindLast() 从数组的末尾开始向前遍历,和上面提到的Find的原理差不多,只不过是倒着来。同样,当找到第一个满足条件的元素时,立即返回该元素。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//从后面找到第一个偶数
Console.WriteLine(Array.FindLast(arr1, FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
我们这里定义的查找偶数的方法和之前一样,数组也一样,只有打印语句不也一样,我们可以对照着1.1看一下。至于Array.FindLast()的参数,不难发现和1.1是一样的,也是通过传入整个数组,然后系统会从末尾向前遍历这个数组,然后找到第一个满足条件的值就返回。这个代码打印的结果是8,我这里就不在展示了,大家可以自己动手敲一下,跑一下看看。
同样,我们思考一下在这次调用里谁是高阶函数,谁是回调函数。不要迟疑,相信自己,Array.FindLast()就是高阶函数,FindEven()就是回调函数。
1.3 Array.FindAll()方法
这个方法只看名字大家应该就知道是干嘛的。顾名思义,是用来找全部的嘛。Array.FindAll() 是 C# 中用于筛选所有数组中符合特定条件元素的方法。它返回一个新数组,包含原数组中所有满足指定谓词条件的元素。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//找到全部偶数
int[] arr2 = Array.FindAll(arr1, FindEven);
//两种打印方式:
Console.WriteLine(string.Join(" ",arr2));
foreach (int i in arr2)
{
Console.Write(i+" ");
}
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
我们还是以判断一个数是否是偶数的这个回调函数为例,这里因为Array.FindAll()方法的返回值是一个数组,所以我们要新建一个数组arr2来接受他的返回值。然后我们这边给大家展示了两种不同的打印方式,第二种foreach大家肯定再熟悉不过了,这里我们来介绍一下第一种。这是string的一个内置api接口,它的作用就是把一个数组拼接成一个字符串,第一个参数“ ”的意思是在每个数组元素中间加一个空格,第二个参数arr2就是我们要转化成字符串的数组。结果如下:

同样,在这个里面Array.FindAll()就是高阶函数,FindEven()就是回调函数。
1.4 Array.FindIndex()方法
Array.FindIndex() 是 C# 中用于查找数组中满足指定条件的第一个元素的索引的方法。它通过遍历数组元素并应用给定的条件来判断是否找到匹配项。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//FindIndex()找满足条件的第一个元素的索引值
Console.WriteLine(Array.FindIndex(arr1, FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
这里他的返回值就是我们要找到第一个元素的下标。我们定义的数组里的第一个偶数是2,下标是1,所以这里就返回1。同样,在这个里面Array.FindIndex()就是高阶函数,FindEven()就是回调函数。
1.5 Array.FindLastIndex()方法
Array.FindLastIndex() 方法用于在数组中从后向前搜索满足指定条件的元素,并返回其索引。如果未找到符合条件的元素,则返回 -1。不难发现,这个就是跟上面的反过来,上面正着查找,下面反着查找。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//从后面找满足条件的元素的第一个索引
Console.WriteLine(Array.FindLastIndex(arr1,FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
我们从后面数第一个偶数是8,下标是7,所以这里的返回值就是7。在这个里面Array.FindLastIndex()就是高阶函数,FindEven()就是回调函数。
1.6 ForEach()方法
这个方法其实和我们的foreach是一样的,说白了就是遍历整个数组,然后按要求操作。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//ForEach()遍历方法 参数1是数组,参数2是遍历函数,这个函数有一个参数,无返回值
Array.ForEach(arr1, Fun_1);
}
public static void Fun_1(int v)
{
Console.Write(v+" ");
}
这里我们新定义一个Fun_1方法,方法体的内容就是输出参数,我们在上面调用这个ForEach()方法相当于就是遍历了这个数组。输出结果就是这个数组的元素。同样在这里Array.ForEach()是高阶函数,Fun_1()是回调函数
1.7 TrueForAll()方法
该方法用于判断列表中的所有元素是否都满足指定的条件。在所有元素都满足条件时候 整体才为true,只要一个不满足条件,整体就为false。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//TrueForAll()所有元素都满足条件时候 整体才为true,只要一个不满足条件,整体就为false
Console.WriteLine();
Console.WriteLine(Array.TrueForAll(arr1, FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
1.8 Exists()方法
该方法用于查找是否有含有满足条件的元素,如果有,不管有一个还是有多个,都返回true。
static void Main(string[] args)
{
int[] arr1 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//查找满足条件的元素,有一个或者多个。整体返回true
Console.WriteLine(Array.Exists(arr1,FindEven));
}
public static bool FindEven(int v)
{
return v % 2 == 0 ? true : false;
}
1.9 其他一些非静态的方法
static void Main(string[] args)
{
//非静态,实例.方法名()
string[] strs = new string[] { "张三", "李四" ,"赵五"};
//输出序列种元素的数量
Console.WriteLine(strs.Count());
//All方法 如果所有元素都满足条件 ,则为true,等同于trueforall
Console.WriteLine(strs.All(Fun_2));
//Any 只要一个满足条件,整体为true 等同于Exists
Console.WriteLine(strs.Any(Fun_2));
Console.WriteLine(strs.GetValue(0));//获取元素值
strs.SetValue("IKUN", 0);//给指定索引值更改元素
Console.WriteLine(strs.GetValue(0));
//int[] 继承于Array Array继承于Object
Console.WriteLine(strs.GetType(). BaseType.BaseType);//GetType ( 获取类型
Console.WriteLine(strs.GetLength(0));//2 指定维度获取长度
}
public static bool Fun_2(string v)
{
return v.Length == 2 ? true : false;
}
这里我就不再给大家一一细讲了,各个方法的功能我都在注释里说明了,这里我把结果给大家:

2.lambda表达式
我们在第一部分时,在向数组高阶方法传递函数的时候比较麻烦,这时候我们可以把函数定义在main函数里面,但其实这个方法并不推荐我们平时使用,这里我们简单提一下。
//例子:
void F1()
{
Console.WriteLine("我定义在main函数里面");
}
F1();
int F2(int a,int b)
{
return a + b;
}
Console.WriteLine(F2(3,5));
当我在主函数调用F1()和F2的时候这个结果是可以被调用的,我们看一下结果:

但上面的写法也不利于用户阅读,这时候我们就可以采用lambda表达式再去进行优化。
lambda表达式:本质是一个函数,作为另外一个函数参数进行使用,也可以称为匿名函数(箭头函数)。其核心特点是无需显式声明方法名或返回类型,直接通过 => 运算符连接参数和函数体。他的表达式语法如下:表达式语法:(参数类型 a,参数类型 b,...)=>{}
lambda表达式也可以找一个变量接收,这个变量是类型使用这三种接收:第一种是Func<> 接收有返回值的函数;第二种是Predicate<> 接收返回值为bool类型的函数;第三种是Action<> 接收无返回值的函数。同时我们要注意:单独写lambda表达式会报错,要么写在高阶函数里面,要么找一个变量接受。
我们接下来来看一些例子:
Func<int, int, int> F3 = (int a, int b) => { return a + b; };//三个int分别是两个传入的变量类型和一个返回值的类型
//lambda可以像普通函数去调用
Console.WriteLine(F3(3,5));
上面的例子就是lambda表达式的一个使用。这里是一个完整的表达,但lambda表达式可以简化,可以把(int a,int b)类型省掉,如果有个参数小括号不能省掉,可以把return和{}一起省掉,具体如下:
Func<int, int, int> F4 = (a, b) => a + b;
Console.WriteLine(F4(12,21));
如果只有一个参数的话,可以把小括号省掉:
Func<int, int> F5 = a => a;
我们也可以把lambda表达式应用在高级函数中:
int[] arr= new int[] { 1,2,3,4,5,6,7,8,9};
Console.WriteLine(Array.Find(arr,a=>a%2==0));
Predicate<>接收返回值为bool类型,所以不用在定义时候 Predicateくint> 写bool类型
Predicate<int> F8 = v => v % 2 != 0;
Console.WriteLine(Array.Find(arr, F8)); //无法从Func<> 转成Predicate<>
最后我们再来举个例子汇总一下:
string[] str = new string[] { "蔡徐坤", "柳智敏", "吉赛尔", "金冬天", "宁艺卓", "易烊千玺" };
//查询第一个长度为4的字符串
Console.WriteLine(Array.Find(str,v=>v.Length==4));
//查询第一个长度为4的字符串的索引
Console.WriteLine(Array.FindIndex(str, v => v.Length == 4));
//查询第一个以“柳”开头的字符串
Console.WriteLine(Array.Find(str,v=>v.StartsWith("柳")));
//查询第一个以“坤”结束的字符串
Console.WriteLine(Array.Find(str,v=>v.EndsWith("坤")));
//查询第一个长度为3并且以“卓”结束的字符串
Console.WriteLine(Array.Find(str,v=>v.Length==3&&v.EndsWith("卓")));
第二部分所有代码的运行结果如下:

本来还说这期给大家在补一节类的继承,我代码都准备好了,但确实没想到这期的篇幅这么长,主播有点想下播了,那就明天再给大家展示类的继承吧,不然篇幅确实太长了,也希望看到这里的家人们理解一下啊,理解万岁,我们下次见!
更多推荐
所有评论(0)