递归示例-指定数字以内的所有排列组合(Reduce)
指定数字以内的所有排列组合:
定义名称版:
=pmtt(指定数字) pmtt=LAMBDA(x,IF(x=1,1,VSTACK(pmtt(x-1),REDUCE(SEQUENCE(x),SEQUENCE(,x-1)^0*x,LAMBDA(a,b,TOCOL(a&SEQUENCE(,b)))))))
不定义名称版:
=LET(fx,LAMBDA(npmtt,x,IF(x=1,1,VSTACK(npmtt(npmtt,x-1),REDUCE(SEQUENCE(x),SEQUENCE(,x-1)^0*x,LAMBDA(a,b,TOCOL(a&SEQUENCE(,b))))))),fx(fx,指定数字))
这个指定数不能太小,1的话,就只有1。
看一下2的结果:
没几个是吧?那就3:
看看这增长的架势,再大点的数就不截图了,且,最大就只能到7。
嗯,才7,返回的值有87万多,一个工作表才一百多万行……
好吧,言归正传,这公式要怎么理解,郑重点,加条分割线吧,顺带居中一下。
***********************************************************************
这公式分成两个部分,递归部分就是一个堆叠,前一个值的结果和当前值的结果堆叠在一起,这没啥好说的,重点是Reduce部分(本文是不是不该归类为递归?)
假设x为2,Reduce部分的公式就可以写成:
=REDUCE(SEQUENCE(2),SEQUENCE(,2-1)^0*2,LAMBDA(a,b,TOCOL(a&SEQUENCE(,b))))
公式返回的结果就是11、12、21、22。
初始值是纵向矩阵1和2,数组就是一个2,然后Reduce的功能就是为迪卡尔积运算而生的,Lambda里使用&连接就可以了,需要注意的是连接的对象不是简单的a&b,而是a连接以b为列数的一行,这里就是横向的1和2。
在这公式里,数组参数的写法明显很累赘,这其实是为递归而设置的具有统一性的一个公式,x为2的时候感觉上去还没啥,再来看当x为3的时候。
好吧,接下来的内容已经没办法在一个平面内正常展示了,只能通过脑电波“搬砖”,就比如a&SEQUENCE(,b),b本身就是一个横向数组,要怎么横向?想说所以才用ToCol?不,ToCol的功能绝不是简单的转成一列,不然把ToCol部分去掉试试,结果就不对了。
那么,一步一步来吧。
第一步运算(这个步子有点大哈):
纵向的1、2、3和横向的1、2、3连接,结果就是11-33的9个值。
ToCol的目的是把这9个值转成一列,然后,这一列就摇身一变,变成了第二步运算的a:
接下来就是新的a和SEQUENCE(,b)的连接。
然后,3个数的所有组合就全部出来了。
好累~
用Reduce实在太BT了,可以用Base吗?
数值是没问题,但其他呢?用了Reduce,参数由Sequence换成引用,那就随便什么都可以组合了,Base的话……不管了,下篇先写个Base的解法吧。