00:00
我们已经了解了scla当中高级计算函数里边的map这一类的操作,它主要是做了一个集合的转换,我们得到的呢,还是一个集合类型。里边的每一个元素做了对应的映射啊,那除了这一类之外,还有一类操作呢,是要把集合里边的所有数据规约聚合到最后的一个结果啊,所以我们把另外一类叫做reduce类的操作,接下来我们就来做一个测试,还是新建一个的object test15同样还是high。Level function式高级计算函数,我们现在是reduce类规约聚合,那同样我们前面还是需要有一个list放在这里,对于这个规约聚合,最后我们可能得到一个值,那我们还是要做一个计算的啊,所以数据少一点,方便我们测试的时候看清楚是怎么回事,就说我们就只要四个数,1234,那么关于盖拉集合当中的规约计算呢,不要提供的接口,这个函数有两个,一个又叫做reduce,所谓的规约简化啊,那另外一种叫做折叠fold,我们先来讲reduce。
01:26
首先我们就直接调这个方法吧,我们直接这个reduce list,直接做一个reduce操作,看有一个方法就叫做reduce,它里面要传什么东西呢?分数里边很明显传的是一个operation op。那么operation呢,本身是一个函数了,拉姆达表达式,这里面的类型我们看的很明显,当前的数据类型啊,大家看这个。当前的泛型就是A1对吧,那么我们就看当前的这个数据传进来之后。
02:00
那就是每两个数据我都要做一次判断,然后呢,做一次规约,得到的同样的数据类型的一个结果,哎,那就是第一个数和第二个数来了之后,哎,规约一次得到一个数,那接下来呢,得到的这个结果再作为第一个数跟第三个数再去做下一次的规约,那就是逐个往后去做规约,这自然就是我们想到的reduce了。啊,那其实大家看到这个reduce它的底层调用是调了什么呢?是一个reduce left,那所谓的reduce left是什么?当然就是从左到右做这样的一个规约了啊,那接下来我们就还是在代码里边给大家看一看结果吧,呃,比方说这个reduce啊,它到底能做什么事呢?里边要传一个规约的函数啊,这个函数其实就代表我们这个规约的操作。对于规约,最简单的规约,我们前面其实已经做过了,大家看前面我们这个简单函数里边求和,这不就是把所有的集合元素最后要得到一个结果输出吗?
03:06
啊,那所以这其实求和就是一个规约,而且我们这里就是从左到右依次做的操作,就是叠加啊,那家想如果现在我们把这个sum啊,这是直接。把它已经特化了,当前一定要sum,就是直接做加法操作,做规约,那现在如果我们把它统一用这个reduce做一个实现,应该怎么实现呢?其实非常简单,那就是传一个拉姆的表达式,我们这里的分数那不就是一个,目前一个A一个B2个数要做规约,那么规约呢,拉来表达式,那当然就是返回A加B了,不是这样做吗?啊,而且大家知道这个非常容易写成一个。拉德表达式简化之后的那个状态,那就是下划线加下划线不就是我们想要的直接对它规约的一个结果嘛,啊,那当前我们可以把它做一个打印输出本身得到其实就是一个int类型的值,所以我们可以直接把它打印啊,看一下结果怎么样。
04:11
大家看到结果是十啊,那我们都知道1234加起来就是十嘛,没有问题,我们看到这里边报黄报警,呃,报警告啊,它其实也是说直接没必要做这样的一个reduce,判断出来了,你不就要做家吗?啊,用sum就搞定了,我们这里只是给大家理解的更加深刻一点啊,可以用这种方式来实现,当然了,前面我们在源码里面也看到了reduce的底层啊,其实是reduce left,那所以这里边我们也可以做一个reduce left,同样它里边呢也是要传一个函数,那这里边其实跟我们前面的那个过程是一样的啊,不过它的这个reduce left就会更加的。就是更加的灵活一点,这里边我们传的这个,大家看到这个聚合的状态跟我们当前这个数据的对应的这个类型呢,可以不同,之前我们那个它它本身,呃,当前都是相同的啊,我们现在是可以不同,所以接下来我们这里直接给一个同样下划线,加下划线也可以得到对应的结果,那自然大家想到可以reduce left,是不是就可以reduce right呢?我们直接看确实是有reduce right,那它代表的含义是什么呢?这个也非常好理解啊们reduce left是从左往右一个一个加,那reduce说right不就应该是从右往左一个一个加吗?哎,这个就很容易想到,那现在我们可以直接运行看看得到的结果到底是什么,没有问题,三个十直接可以搞定,接下来我们换一行。
05:57
那么关于这个reduce left和reduce right,还需要再给大家做一个详细的介绍,就是因为这里面大家如果直观看的话,那可能会觉得,哎,这个确实没有问题啊,就是你这个加法的话,从前往后加,或者从后往前加嘛,哎,那这里边我们再给大家举另外的一个例子,比方说啊,我们再定义一个例子二。
06:24
还是用半数对象去把它定义出来。比方说我们当前是三四。5R10它的五数,那现在呢,我们定义的不是做一个加法操作,不是逐逐个相加,逐个相加,你左右这个顺序都一点关系都没有吗?现在我们要做的是减法操作,哎,那所以接下来我们就要判断一下啊,直接printline目前的LIST2,如果掉了reduce下划线,点下划线的话,这得到结果应该是多少?
07:01
哎,我们首先来运行啊,大家可以推测一下当前应该得到什么啊,哎,自然我们就想到这应该是从左到右一个一个减吧,哎,当前这个三减四,那应该是应该是负一,然后接下来这个四得到负一,再减五,那应该是负六,负六,再减八,负14,最后应该是负24,我们可以直接运行一下,看看符不符合预期,诶,这个没有问题啊,负24这个是对的。那我们也知道line打印这个list2.reduce,如果要是left的话,本身上面那个reduce底层就是reduce left这个肯定也是24,不会有任何的问题。关键问题就在于,如果我们这里要是reduce right呢?如果改成reduce right,我们当前的结合,结合的顺序又应该是什么样子?
08:03
有同学可能讲了啊,那这个很简单吧,从右往左减吧,那就是十减822减五负三负三减四负七负七,再减三负十啊,那这个看起来比较简单,负十是不是这样呢?我们可以运行一下,看看最后的结果。不是负十,居然是正六,哎,这个它为什么会是一个正六呢?这里我们可以简单的点到源码里面,给大家稍微的看一下啊,做一个简单的分析,这边点进来之后reduce right,这里大家看到最后它其实是做了一个就是把这个op啊,我们当前这个操作传进来,他这里边做了一个什么操作呢?首先判是否为空对吧,然后判断是否它的ta为空。我们之前说的T这个尾啊,它其实是一个列表,就是除了头剩下的都是尾啊,所以它是判断,如果尾是空的话,那说明现在只有一个元素,只有一个had嘛,那所以就直接返回had就行了,Reduce right就一个数,就had,那如果不是这些特殊情况,它返回的是什么呢?
09:13
这是一个递归调用。诶,我们看到当前大家看到就是直接op操作啊,调当前的这个这个操作,然后传进来的是什么呢?传进来的变成了had和Q点reduce right。把这个传进来,所以整体来看的话,就相当于是我以因为我们前面这个数据大家可以认为是当前要聚合的。就是第一个第一个数就可以认为是聚合的状态嘛,然后后边这个呢,就是我们想要,呃,进一步啊,想要去跟它做结合的那个数据,那现在呢,我们是把had。一开始的这个数据放在开始的位置,然后后边呢是递归调用tail的reduce right。
10:04
所以现在大家把这个当前的列表如果放在这儿的话,我们其实把头放在这儿后边的这一串。要去执行reduce right,那接下来他在执行的时候又怎么样呢?是不是又把头放在这儿隔开剩下的执行reduce right呀,一层一层递归下去,最后要算的是什么呢?其实就是最后两个数要执行当前的reduce right。哎,那所以当前我们的执行结果是。对于我们前面的这个例子而言啊,要注意并不是直接十,反过来十减八减五减四减三,而是什么呢?而是三减去后边完整的结果,然后四减去后边完整的结果,五减去后边八减十的结果,这样的一个计算过程。
11:03
所以减十我们知道负二五减负二变成了正七,四减正七是负三,三减负三是正六,所以我们最后得到的结果是六是对于reduce right的一个一层源码的解释,大家需要稍微的注意一下。
我来说两句