乐于分享
好东西不私藏

WPS能用MAP和MAKEARRAY,为何嵌套LAMBDA仍不行

WPS能用MAP和MAKEARRAY,为何嵌套LAMBDA仍不行

WPS能用MAP和MAKEARRAY,为何嵌套LAMBDA仍不行

摘要

同一份订单明细,要按客户横向排出全部订单号,Excel 和新版 WPS 都能用 LETMAPMAKEARRAY 写成一条溢出公式。真正拉开兼容性差异的,不是 LAMBDA 这个函数本身,而是让一个 LAMBDA 返回另一个 LAMBDA,再把返回值当函数调用。本文用一张 WPS 实测截图把这两个层次分开,也给出一条 Excel 和 WPS 都能计算的公式。

一、订单要横着排,公式从哪里变复杂了

1.1 一列明细,右侧要变成每客户一行

1.1.1 订单数量并不相同

假设 A2:B8 是一份订单明细。A 列是客户,B 列是订单号:

客户 订单号
华东门店 SO-1001
华南门店 SO-1002
华东门店 SO-1003
华北门店 SO-1004
华南门店 SO-1005
华东门店 SO-1006
华北门店 SO-1007

我希望得到的是一张横向清单。华东门店有三张订单,华南和华北各有两张,短的那一行在最后补空白:

客户 订单1 订单2 订单3
华东门店 SO-1001 SO-1003 SO-1006
华南门店 SO-1002 SO-1005
华北门店 SO-1004 SO-1007

这篇文章接着前一篇关于 MAP 返回数组与 LAMBDA 打包的说明。前文的 packed 写法在 Excel 内部计算可以成立;这次把同一需求放到 WPS 测试,才发现兼容差异不在动态数组函数是否存在,而在 LAMBDA 返回后能否继续被调用。

直接写成 MAP(names,LAMBDA(n,FILTER(orders,customers=n))) 不行。每个客户筛出的订单数不同,MAP 会收到“数组里的数组”,Excel 会报 #CALC!。因此,最终公式必须先决定结果区域有几行、几列,再让每个位置只返回一个订单号。

二、这条公式在 Excel 和 WPS 都能计算

2.1 让 MAKEARRAY 每次只拿一个值

2.1.1 不保存函数,直接按坐标筛选

下面的公式从 A2:B8 读取明细,结果从公式所在单元格向右下方溢出:

=LET(

    customers,A2:A8,

    orders,B2:B8,

    names,UNIQUE(customers),

    width,MAX(MAP(names,LAMBDA(n,SUM(–(customers=n))))),

    HSTACK(

        names,

        MAKEARRAY(

            ROWS(names),

            width,

            LAMBDA(

                r,c,

                IFERROR(INDEX(FILTER(orders,customers=INDEX(names,r)),c),“”)

            )

        )

    )

)

这里的 width 先计算某个客户最多有几张订单。MAKEARRAY 随后逐格工作:r 表示第几个客户,c 表示该客户的第几张订单。FILTER 先得到该客户的纵向订单清单,INDEX(...,c) 只取其中一个值。订单不够时,IFERROR 返回空文本。

我刻意没有在公式里建立 packed 变量,也没有让 LAMBDA 作为中间结果留在数组中。MAKEARRAY 的每次回调都返回标量,最终拼出的只是一个普通的矩形数组。

2.2 WPS 的实测结果

2.2.1 公式编辑器和溢出区域同时给出了结果

下图是在 WPS Office 12.1.0.22529 中输入上面公式的结果。左侧 D:G 已经溢出为三行客户和对应订单,右侧公式编辑器显示的是同一条 LET 公式。

这张图说明 WPS 能识别并计算 LETUNIQUEMAPLAMBDAFILTERMAKEARRAYHSTACK,而且这条公式确实返回了预期的 3 行订单清单。

2.3 Excel 的实测结果

2.3.1 同一条公式得到同一张溢出表

Excel 中输入相同公式,D:G 的溢出结果也与 WPS 一致。公式编辑区和结果区域都在同一张图里,订单的排列顺序没有变化。

两张实测图放在一起看,结论就比较明确了:新版 WPS 和 Excel 都支持本文这条“逐格筛选”的 MAKEARRAY 写法。它们的共同点是,LAMBDA 只承担回调,回调的结果始终是单元格值。

三、支持 LAMBDA,不等于支持函数值继续流转

3.1 两种用法看起来只差一层,计算器看到的不是一回事

3.1.1 新公式把 LAMBDA 当作回调

兼容公式里的两个 LAMBDA 都是高阶函数的回调参数:

=MAP(names,LAMBDA(n,SUM(–(customers=n))))

=MAKEARRAY(ROWS(names),width,LAMBDA(r,c, … ))

MAP 把当前客户名交给第一个回调,回调返回一个订单数。MAKEARRAY 把行号和列号交给第二个回调,回调返回一个订单号或空白。它们的返回结果都是普通值,因此 Excel 和上图所示版本的 WPS 都可以把结果组成工作表数组。

原先那条 Excel 专用写法多走了一步。它先让外层 LAMBDA 返回一个尚未执行的内层 LAMBDA

=MAP(

    names,

    LAMBDA(n,LAMBDA(TOROW(FILTER(orders,customers=n))))

)

随后再用 INDEX(packed,r,1)() 取出第 r 个函数并调用。Excel 能把这个返回的 LAMBDA 保留在同一条 LET 公式的内部计算过程中,最后由 MAKEARRAY 逐格取值。

3.2 WPS 卡在“返回后再调用”这一步

3.2.1 用一个最小公式就能看出边界

我在同一版本的 WPS 里分别测试了几个公式:

公式 WPS 结果
=LAMBDA(x,x+1)(1) 返回 2
=MAP(A2:A8,LAMBDA(n,n)) 正常溢出
本文的 MAKEARRAY 公式 正常返回订单清单
=LET(f,LAMBDA(x,LAMBDA(x+1)),f(1)()) 将尾部 () 判为括号使用错误

先看 Excel。公式栏显示的是完整的 =LET(f,LAMBDA(x,LAMBDA(x+1)),f(1)()),单元格 I5 的计算结果为 2。这说明 Excel 能先得到内层 LAMBDA(x+1),再执行紧跟在 f(1) 后面的第二组括号。

WPS 对同一条公式的处理不同。它把 f(1)() 中用于调用返回函数的那组空括号提示为“公式中括号使用错误”,并建议改写成没有内层 LAMBDA 的另一条公式。

截图弹窗里的“公式结果:2”对应的是 WPS AI 给出的更正公式 =LET(f,LAMBDA(x,x+1),f(1)),不是原始嵌套公式已经计算成功。原式被判错,正好说明 WPS 没有把 f(1) 的返回结果当作可继续调用的 LAMBDA

最后一行就是分水岭。外层 LAMBDA 的结果不是数字、文本或数组,而是另一个 LAMBDAf(1)() 又试图立刻调用这个返回的函数。WPS 12.1.0.22529 不支持这段组合,因此完整的 packed 写法同样无法计算。

所以,问题不能概括成“WPS 不支持 LAMBDA”。=LAMBDA(x,x+1)(1) 已经证明普通的定义和调用没有问题。更准确的说法是:在这次实测的 WPS 版本中,公式引擎不能完成“LAMBDA 返回 LAMBDA,再对返回值加 () 调用”这一层函数值传递。

四、为什么改写后两边都能接受

4.1 函数没有离开自己的调用位置

4.1.1 计算过程始终回到单元格值

兼容公式里,LAMBDA 只出现在 MAPMAKEARRAY 的参数位置。WPS 在执行到回调时马上给它传入 n,或者传入 rc,回调立刻交回数字、文本或空文本。没有任何一个数组元素需要保存为“以后再执行的函数”。

这也是我更愿意把它作为跨 Excel 和 WPS 的默认写法的原因。它没有绕开 #CALC! 的嵌套数组限制,却把原本会成组返回的订单,拆成了目标矩形区域中的单个格子。公式的工作量和结果形状都更直观。

4.2 两个版本都要先识别这些函数

4.2.1 出现 #NAME? 时,先查版本而不是改括号

本文的兼容结论只覆盖能识别 LETUNIQUEMAPLAMBDAFILTERMAKEARRAYHSTACK 的 Excel 与 WPS。若输入公式后出现 #NAME?,说明当前版本缺少其中至少一个函数,这时不是把 packed 删除就能解决的问题。

我会先从 =LAMBDA(x,x+1)(1)=MAP({1,2},LAMBDA(x,x))=MAKEARRAY(1,1,LAMBDA(r,c,1)) 这类短公式开始检查。哪个函数不识别,就按实际版本升级,或者改用辅助列、透视表等更传统的整理方式。

五、写在最后

5.1 兼容性要看组合,不只看函数清单

5.1.1 同名函数可用,嵌套方式仍可能不同

公式兼容性最容易误判的地方,是看到 WPS 能输入 MAPLAMBDAMAKEARRAY,便以为 Excel 的组合写法都能照搬。这个订单清单的例子正好相反:函数名都能识别,但“先返回函数,再调用返回值”跨过了 WPS 当前公式引擎的边界。

把筛选动作放回 MAKEARRAY 的逐格回调后,公式不再依赖函数值传递,Excel 和 WPS 都能把它落成同一张订单清单。以后遇到类似的兼容问题,我会先拆出最小公式,确认究竟是哪一层组合失败,再决定是换函数,还是只改返回值的组织方式。

如果你也经常用 Excel 和 VBA 处理表格里的兼容性问题,欢迎关注“VBA爱好者”。