ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 3290|回复: 24

[原创] LAMBDA函数递归:m选n所有组合问题

[复制链接]

TA的精华主题

TA的得分主题

发表于 2022-12-2 11:46 | 显示全部楼层 |阅读模式
本帖最后由 shaowu459 于 2022-12-2 22:40 编辑

9楼有更新算法的文件,可以下载参考。

题目要求说明:假设m、n均为自然数,且n≤m,现在要求列出从m个数字中选出n个数字的全部组合。

组合数量在Excel中可以使用COMBIN函数计算出来,例如5个数中选3个数的组合数=COMBIN(5,3)=10。在LAMBDA函数出现之前,Excel工作表函数应该无法完成此项工作,本例主要介绍如何使用LAMBDA函数的递归功能实现列出m选n所有组合的问题。


图片.png

m选n组合(递归)-超人.rar

370.52 KB, 下载次数: 84

评分

8

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 12:15 | 显示全部楼层
以5选3来说明一下递归的大概思路,m=5,n=3:
1)假设定义的递归函数为fx,则5选3表示为=fx(5,3)。
2)首先,从1、2、3、4、5之中选出第一个数字1,剩余的问题转化成从剩余的2、3、4、5这4个数字中提取出2个数字,也就是fx(m-1,n-1)=fx(4,2)。
3)从2、3、4、5这4个数字中提取出2个数字时,先提取出第一个数字2,剩余的问题转化成从剩余的大于2的3、4、5(如果不设定这个条件,生成的组合会有重复)这3个数字中提取出1个数字,也就是fx(4-1,2-1)=fx(3,1)。
4)当n=1的时候就可以停止递归了,这时的数组中有几个数字,就可以直接和前面的数字直接组合了。另外,当剩余的问题变成fx(m,n)并且m=n的时候,例如从剩余5个数字中提取5个数字,这时只有一种选择,也就可以停止递归运算了。
5)第3步中循环完第一个数字2后,要循环第2个数字3,这时要从剩余的大于3的数字4、5中选出一个数字,问题变成fx(2,1),因为n=1,所以也可以终止递归运算。
6)第3步中循环完第二个数字3后,要循环第3个数字4,但是大于4的数字只有1个5,无法实现从1个数字中提取2个数字,因此,此次循环保留原来的值不变,相当于跳过此次循环的运算。同样道理,循环到数字5时也跳过循环运算。
7)此时,第3步的循环完成,将返回循环第2步中的第2个数字2,要从大于2的3、4、5这3个数字中选择2个数,也就是fx(3,2),以此类推。如果大于当前循环数字的数字个数小于需要提取出的数字个数,就跳过此次循环运算。

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 12:23 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
根据2楼的分析逻辑,我们可以定义一个名称fx,公式如下:
  1. =LAMBDA(x,y,IFS(y=1,x,ROWS(x)=y,TOROW(x),1,DROP(REDUCE(0,x,LAMBDA(m,n,IF(ROWS(x)-MATCH(n,x,)<y-1,m,VSTACK(m,IFNA(HSTACK(n,fx(DROP(x,MATCH(n,x,)),y-1)),n))))),1)))
复制代码
图片.png

定义完名称后,在任意空单元格输入以下公式即可获得需要的组合情况(SEQUENCE生成1至m的自然数序列):
  1. =fx(SEQUENCE(15),8)
复制代码
图片.png

由于递归的运算速度问题,建议不要用太大的数字测试。我自己在工作表中测试20选8的所有组合,共125970个,回车后20秒工作表才返回全部结果。

评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2022-12-2 12:33 | 显示全部楼层
作为真菜鸟级别入门的,新版这函数完全可以划入VBA版块。

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 12:35 | 显示全部楼层
本帖最后由 shaowu459 于 2022-12-2 22:56 编辑

下面简单介绍一下公式的思路:

=LAMBDA(x,     生成1-m的自然数序列
               y,      需要挑选出的数量n
               IFS(y=1,x,      如果n=1,则直接返回当前的数组终止递归循环
                     ROWS(x)=y,TOROW(x),     如果剩余从m中提取n个数的m=n,则只有一种结果,因此转换成行,退出循环
                     1,DROP(REDUCE(0,
                                              x,
                                              LAMBDA(m,
                                                           n,
                                                           IF(ROWS(x)-MATCH(n,x,)<y-1,   判断下一步拟提取的基数m是否小于下一步要提取的数字n
                                                          m,    如果是,则保持m不变,跳过此次循环运算
                                                           VSTACK(m,
                                                                       IFNA(
                                                                               HSTACK(n,   将当前的数字和fx(新数组,n-1)生成的结果进行堆积
                                                                                            fx(DROP(x,MATCH(n,x,)),y-1)),n))))),1)))    将当前数组中循环数字前面的行都去掉,作为重复调用fx的第一参数,将y-1(也即n-1)作为重复调用fx的第二参数,生成fx(m-1,n-1)的结果

评分

4

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 13:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
jivy1212 发表于 2022-12-2 12:33
作为真菜鸟级别入门的,新版这函数完全可以划入VBA版块。

基础循环和递归层面,确实有点像vba。

TA的精华主题

TA的得分主题

发表于 2022-12-2 14:37 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 14:56 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
alan57 发表于 2022-12-2 14:37
大强大了,看半天都是拟懂非懂的。

拿5选3,手动模拟一遍,就清晰了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-2 20:51 | 显示全部楼层
更新递归的算法,这个效率高的多:
  1. =LAMBDA(m,n,IF(n=1,m,IF(ROWS(m)=n,TOROW(m),VSTACK(IFNA(HSTACK(@m,gx(DROP(m,1),n-1)),@m),gx(DROP(m,1),n)))))
复制代码


m选n组合(递归)-超人.rar

1.24 MB, 下载次数: 94

评分

5

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2022-12-3 21:04 | 显示全部楼层
本帖最后由 shaowu459 于 2022-12-3 21:06 编辑

9个及以下元素全排列(9个有36万多个结果,回车后稍等能正常返回,10个362万多个结果无法全部返回):
定义名称fx:
  1. =LAMBDA(z,IF(COUNT(z)=1,z,DROP(REDUCE(0,z,LAMBDA(x,y,VSTACK(x,IFNA(HSTACK(y,fx(FILTER(z,SEQUENCE(,COUNT(z))-MATCH(y,z,)))),y)))),1)))
复制代码
图片.png

评分

1

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-29 02:11 , Processed in 0.036509 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表