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("卓")));

第二部分所有代码的运行结果如下:

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

更多推荐