HI,大家好,我是星光。
上一期给大家聊了BYROW函数,末尾留了一个多关键词查询的案例,当时我们说,当计算对象是单列多行数据时,用MAP函数比BYROW函数更适合。这期就给大家聊一下MAP函数。 👆点击图片阅读BYROW函数教程 ▎语法概要 1)基础语法 以下是MAP的语法格式: =MAP( 数组, 数组或LAMBDA自定义表达式1, 数组或LAMBDA自定义表达式2, …… 数组或LAMBDA自定义表达式n )
第1参数是数组,第2等参数是数组或LAMBDA表达式。系统按照从上到下、从左到右的顺序,遍历数组中的每个元素,执行LAMBDA表达式,最后返回和源数组尺寸相同的结果数组。 打个响指,看语法看不出花来,我们还是举个简单的例子。 如上图所示,是一张成绩表。现在,需要对每个人的语文成绩加10分。为什么加10分呢?听说是庆祝祖国即将统一了。 MAP函数的解法如下: =MAP(D2:D9,LAMBDA(_m,_m+10))
MAP函数第1参数是D2:D9,系统从上到下依次遍历数组中的每个元素,也就是D2/D3/D4/...D9,每个元素执行LAMBDA表达式。 LAMBDA表达式第1参数属于自定义名称(_m),指向第1个数组中每个被遍历的元素,第2参数是计算方式(_m+10),在原值的基础上加10。 公式返回结果如下图所示。 …… 2)遍历顺序
当MAP函数的数组参数是多行多列时,会按照从上到下、从左到右的顺序遍历。 还是举个简单例子。以同样的数据为例,不但语文要加10分,数学也要加10分。嗯,快乐总是相似的。 MAP函数解法如下: =MAP(D2:E9,LAMBDA(_m,_m+10))
MAP函数第1参数是D2:E9,8行2列。系统按照从上到下、从左到右的顺序遍历该数组,也就是D2/E2/D3/E3……依次执行LAMBDA表达式,每个元素+10,返回一个和源数组尺寸相等的结果数组,8行2列,如下图所示: …… 3)多数组参数 MAP函数支持多个数组作为参数。 例如,需要计算每个人的成绩总分,MAP函数解法如下: =MAP(D2:D9,E2:E9, LAMBDA(_a,_b,_a+_b))
MAP函数第1参数是源数组1:D2:D9,第2参数是源数组2:E2:E9;第3参数是LAMBDA表达式。 LAMBDA第1个参数是自定义名称(_a)指向源数组1,第2个自定义名称(_b)指向源数组2。系统按顺序遍历源数组中的每个元素,_a依次指向D2/D3/..D9。_b依次指向E2/E3/..D9,两者依次相加即为每个人的成绩总分。 从这个计算规则中,你就可以发现,当数组有多个时,它们的尺寸大小必须一致,不然按照数组运算规则,会导致配对元素缺失,进而产生错误值。 ……
4)保留引用特性 和BYROW函数一样,但源数组为引用时,MAP也会保留引用的特性。摊手,如果你忘记了什么是引用,最好是重新看下新手教程里的什么是Excel数据类型章节。 举个简单的例子。 如上图所示,需要在G列用动态数组的形式,统计每个班级累加出现的次数。 MAP函数参考解法如下: =MAP(A2:A9, LAMBDA(_m,COUNTIF(A1:_m,_m)))
MAP第1参数是引用性质的数组A2:A9,系统遍历该数组每个元素,执行LAMBDA表达式。_m指向源数组被遍历的元素,比如A2,COUNTIF函数第1参数是A1:_m,表示统计范围,比如A1:A2,在这个范围中统计A2出现的次数。下一个遍历元素为A3,_m指向A3,COUNTIF在A1:A3中统计A3出现的次数……其余以此类推。 ▎实战案例 坦白但不露胸说,以上案例,都是简单的,只是为了表达MAP函数的运算特点,很明显,它们并非MAP不可。MAP函数最常用的场景还是将计算结果作为内存数组的形式,传递给其它函数。换句话说,它只是一个计算过程,而非最终结果。
再举两个例子,这两例子虽然实际工作中不常见,但计算过程比较典型。更多实用的案例,可以参考我们的100道练习题系列。 1)字符串筛选、拆分与合并
如上图所示,A列的数据混合了班级、姓名和性别等数据,需要从中获取男性的名单,并合并成一个字符串。
参考解法如下: =TEXTJOIN('-',1, MAP(A2:A9, LAMBDA(_m, IF(RIGHT(_m)='男', INDEX(TEXTSPLIT(_m,'-'),2), '') ) ) )
MAP函数遍历A2:A9区域,如果最右边的字符不为男,则返回假空,否则使用TEXTSPLIT函数按分隔符'-'将其拆分,再使用INDEX函数取出姓名。 2)字符串拆分与内部计数 如下图所示,A2:A8单元格内存在多个人名,不同人名之间使用分隔符'-'相连。
现在需要统计每个单元格内部每个人名累加出现的次数,模拟结果如下: MAP函数参考解法如下,B2单元格输入以下公式向下复制填充。 公式看不全可以左右拖动.. =LET( _a,TEXTSPLIT(A2,'-'), _b,SEQUENCE(1,COUNTA(_a)), TEXTJOIN('-',1, MAP(_a,_b, LAMBDA(_x,_y, _x&COUNT(0/((_a=_x)*(_b<=_y)))&'次') ) ) )
第2行代码使用TEXTSPLIT函数将A2单元格按分隔符'-'拆分,并赋值变量_a。 {'看见星光','二肥','超人','看见星光','看见星光'}
第3行代码统计数组_a元素的个数,生成一个递增水平序列,赋值变量_b。 这个时候,我们就可以假设,得到了一个虚拟的二维数组,如下图所示:
然后,我们使用MAP函数,遍历这个虚拟数组。 MAP函数第1参数为_a,为每个人名元素,第2参数_b,为水平序列。在LAMBDA表达式中,使用COUNT函数统计所有人名等于当前人名,并且所有序列小于等于当前序列的个数,也就是每个人名累加出现的次数。
最后使用TEXTJOIN函数将结果合并即可。
……
当我们使用了显性遍历的函数,诸如MAP/BYROW/SCAN/REDUCE等时,最好使用动态数组的形式,一次性返回全部结果,这可以避免反复调取单元格对象到内存中,以至于严重拖累计算速度——这也是我们一直说的,如果WPS不支持动态数组,则引入Excel新函数体系无意义,因为它压根带不起这批函数的计算速度。
以上述问题为例,如果使用一条函数公式,返回B列全部计算结果,可以在外部嵌套一个REDUCE函数。在B1单元格输入以下公式即可:
=REDUCE('数据',A2:A8,LAMBDA(_p,_v, LET( _a,TEXTSPLIT(_v,'-'), _b,SEQUENCE(1,COUNTA(_a)), _c,TEXTJOIN('-',, MAP(_a,_b,LAMBDA(_x,_y, _x&COUNT(0/((_a=_x)*(_b<=_y)))&'次') )), VSTACK(_p,_c) )))
……
摊手,今天给大家分享的内容就这样吧,有啥问题照例可以在VIP会员群中提问交流↓↓ 挥挥手,关于REDUCE函数的讲解,咱们以后的推文中再见。 需要系统学习Excel,却找不到优质教程?学习Excel的过程中遇到疑难问题,却找不到人及时作出解答?加入我的付费社群,与4500+学员一起,同微软最有价值专家(MVP)全面精进表格之道👇 👀
|