WPS 函数 | 递归!车路线----节点路线全连通查找 !!!
一、帖子开篇
很多朋友做物流站点、路线连通、节点路径查找,都需要根据起点 + 终点,自动找出所有全部连通完整路线。比如我表格里的站点链路:红庙-华隆、华隆-合肥、合肥-繁华、合肥-横溪、横溪-繁华、红庙-昆山、昆山-芜湖、芜湖-繁华给定一组起点-终点,自动遍历所有连通路径,把整条串联路线完整提取出来。
今天直接把我这套纯 WPS 原生函数、无 VBA、纯 LET + 多层 LAMBDA 递归、正则动态匹配的完整公式,从函数定义、每一层 Lambda 含义、递归循环逻辑、正则拼接坑、整条公式运行全流程,从头到尾掰开揉碎讲清楚,附带每一行代码注释、底层原理、新手易错点。
你的完整原始公式(先放全文):
excel
=LET(
下一站,
LAMBDA(a, FILTER(LEFT(a, LEN(a) - 2) & B:B, RIGHT(a, 2) = LEFT(B:B, 2), a)),
下站循环,
LAMBDA(a, IF(ROWS(a) = 1, 下一站(a), VSTACK(下一站(TAKE(a, 1)), 下站循环(DROP(a, 1))))),
终点循环,
LAMBDA(a, IF(AND(IFNA(下站循环(a) = a, )), a, 终点循环(下站循环(a)))),
判断提取,
LAMBDA(a,
TOCOL(UNIQUE(REGEXEXTRACT(终点循环(MID(a, 1, 2)), ".*"&MID(a, 4, 2)&""), 3))),
判断提取(E10))
二、业务场景 & 表格数据源
先统一所有背景,所有人都能看懂:
数据源区域:B列,全部是单向路段,格式统一 起点-终点
例:红庙-华隆、合肥-繁华、芜湖-繁华
查询格式:你 E 列的查询单元格,统一格式 起点-终点
例:红庙-繁华、合肥-繁华
公式需求
输入任意一组起点-终点,自动递归遍历所有连通路段,输出全部完整串联路线
比如查询红庙-繁华,自动输出全部 3 条连通路径:
plaintext
红庙-华隆-合肥-繁华
红庙-华隆-合肥-横溪-繁华
红庙-昆山-芜湖-繁华
技术栈全部原生函数:LET容器 + 4 层自定义LAMBDA函数 + 多层递归 + FILTER数组遍历 + VSTACK数组堆叠 + MID文本截取 + REGEXEXTRACT正则动态匹配 + UNIQUE去重 + TOCOL一维数组展开
三、逐行逐函数完整拆解
LET函数的本质:提前定义好所有自定义函数 / 变量,后面统一调用,公式整洁、只计算一次、不重复运算。里面依次定义了 4 个自定义函数:下一站 → 下站循环 → 终点循环 → 判断提取,层层嵌套、层层递归,我逐个讲透。
1. 第一层自定义函数:下一站
excel
下一站,
LAMBDA(a, FILTER(LEFT(a, LEN(a) - 2) & B:B, RIGHT(a, 2) = LEFT(B:B, 2), a)),
函数含义(核心基础函数,整条公式的地基)
自定义函数名:下一站(a)传入一个路段文本a,自动查找这个路段的终点,在 B 列所有路段里,能衔接上的「下一段完整路段」
逐代码字符拆解
LAMBDA(a, ...)
定义匿名函数,形参a:就是你传入的当前路段(比如红庙-华隆)
RIGHT(a, 2)
截取传入路段a的最后 2 个字符,也就是当前路段的【终点】
例:传入红庙-华隆,RIGHT(a,2) → 结果华隆
LEFT(B:B, 2)
批量提取整个 B 列所有路段,每一条的前 2 个字符,也就是每一条路段自身的【起点】
匹配条件 RIGHT(a, 2) = LEFT(B:B, 2)
筛选逻辑:上一条路的终点 = 下一条路的起点,也就是能首尾衔接的路段
LEFT(a, LEN(a) - 2) & B:B
路段拼接核心!
LEFT(a, LEN(a)-2):把传入的原路段a,去掉末尾的终点,保留完整前缀路径
& B:B:把前缀路径,和后面匹配到的衔接路段,全部拼接起来,形成更长的串联路径
例:传入红庙-华隆,匹配到华隆-合肥,拼接后直接生成 红庙-华隆-合肥
FILTER(拼接结果, 衔接条件, a)
满足衔接条件,就返回拼接好的更长路径
兜底参数a:如果找不到下一站、无路可走了,就原路返回自身,防止公式报错、数组断裂
总结作用
只做一件事:给定一条路径,自动找所有能接上的下一段路,并且直接拼接成长路径,是所有递归循环的基础单元。
2. 第二层自定义函数:下站循环
excel
下站循环,
LAMBDA(a, IF(ROWS(a) = 1, 下一站(a), VSTACK(下一站(TAKE(a, 1)), 下站循环(DROP(a, 1))))),
函数含义
自定义函数名:下站循环(a)数组批量循环版的「下一站」解决问题:上一层下一站只能处理单条路径,这个函数可以处理一整个路径数组,数组里每一条路径,全部独立去跑下一站查找,互不干扰,递归遍历。
逐代码字符拆解
LAMBDA(a, ...)
形参a:传入的路径数组(多条路径组成的一维数组)
IF(ROWS(a) = 1, 下一站(a), ...)
IF 分支判断,递归终止判断条件:
当数组a只有1 行(单条路径):直接调用第一层下一站(a),找它的下一站拼接
当数组有多行多条路径:走后面的数组拆分递归逻辑
TAKE(a, 1)
提取数组a的第 1 行(第一条路径),单独拿出来
下一站(TAKE(a, 1))
单独给第一条路径,跑一遍「找下一站 + 拼接」
DROP(a, 1)
把数组a去掉第一行,拿到剩下所有的其余路径
下站循环(DROP(a, 1))
自身递归调用! 把剩下的路径数组,再次扔进下站循环函数里,循环处理
VSTACK(...)
把「第一条路径的结果」+「剩余数组递归完的全部结果」,上下堆叠合并成一个完整新数组
递归逻辑全程白话
3. 第三层自定义函数:终点循环
excel
终点循环,
LAMBDA(a, IF(AND(IFNA(下站循环(a) = a, )), a, 终点循环(下站循环(a)))),
函数含义
自定义函数名:终点循环(a)整条公式的灵魂!深度递归遍历全链路传入一个初始起点路径,无限循环找下一站、拼接路径,直到走到死胡同、再也没有能衔接的路段为止,自动走完从起点出发的所有全部连通完整路线。
逐代码字符拆解
LAMBDA(a, ...)
形参a:传入的初始起点(你后面 MID 截取出来的起点文本)
核心递归终止条件 IF(AND(IFNA(下站循环(a) = a, )), a, ...)
我拆开这个嵌套条件,新手最容易懵的地方:
下站循环(a):把当前路径,跑一遍全数组找下一站,得到新一轮延伸后的路径
下站循环(a) = a:判断延伸后的路径,和原来的路径是不是完全一模一样
含义:找不到任何新的衔接路段了,无路可走、已经走到链路终点了
IFNA(...,):屏蔽无匹配报错,找不到结果时返回逻辑值,防止数组报错中断
AND(...):全数组判断,所有路径全部无路可走,整体判定终止
条件成立(无路可走):a 直接返回当前已经走完的完整路径
递归分支 终点循环(下站循环(a))
自身无限递归
只要还能找到下一站、路径还能延伸,就:
当前路径 → 跑下站循环延伸变长 → 把新路径,再次丢回终点循环自身函数,继续找下一站、继续拼接
全程递归白话逻辑(重中之重)
plaintext
传入初始起点
第一步:找所有能衔接的下一站,拼接成长路径
判断:还能不能继续往后走?
能走 → 把新路径重新扔进自己函数,继续延伸
不能走(无路可走)→ 停止递归,返回最终完整全链路路径
完美实现从起点开始,深度遍历所有连通支路,走完所有路线。
4. 第四层自定义函数:判断提取
excel
判断提取,
LAMBDA( a,
TOCOL(UNIQUE(REGEXEXTRACT(终点循环(MID(a, 1, 2)), ".*"&MID(a, 4, 2)&""), 3))),
函数含义
自定义函数名:判断提取(a)对外最终调用入口,承接前面所有递归,完成「查询文本拆分→起点递归全遍历→终点正则筛选→去重→数组展开」全部收尾工作,你最后表格里只需要调用这个函数即可。
逐代码字符拆解(顺带把你之前问的所有正则坑全部讲透)
LAMBDA(a, ...)
形参a:就是你表格里 E 列的完整查询单元格,格式固定 起点-终点
例:a = 红庙-繁华
MID(a, 1, 2)
截取查询文本a的前 2 个字符 → 查询起点
例:红庙-繁华 → 截取结果 红庙
终点循环(MID(a, 1, 2))
把上面截取的起点,扔进我们第三层写好的终极递归函数
自动从起点开始,深度遍历所有连通路线,拼接出所有从该起点出发、能走到的全部完整长路径
MID(a, 4, 2)
截取查询文本a第 4 位开始的 2 个字符 → 查询终点
例:红庙-繁华 → 截取结果 繁华
重点!正则拼接写法(你之前反复问的「正则里面嵌套函数」终极正确写法)
excel
".*"&MID(a, 4, 2)&""
这里把你之前所有踩过的坑一次性讲明白:
错误写法(你之前写的):".*&MID(a,4,2)&.*"
双引号把所有内容全包死,&和MID函数全部被当成纯文本字符,函数完全不计算
正确拼接铁则:固定正则字符写在引号内,函数 / 单元格全部切出引号,用 & 连接符拼接
前缀固定 .* → 写在引号里 "."*
中间动态终点 → 放外面 MID(a,4,2)
后缀固定内容 → 写在引号里 ""
最终拼接:".*"&MID(a,4,2)&""
正则含义:.* 贪婪匹配前面所有内容,只要路径末尾包含我们查询的终点,就全部匹配提取
REGEXEXTRACT(递归全量路径数组, 上面拼接好的动态正则)
从递归跑出来的所有起点全链路里,精准筛选出末尾刚好是你查询终点的所有有效路线,过滤掉所有走到其他终点的无效路径
UNIQUE(..., 3)
数组去重,参数3:整行完全重复才剔除,保留所有不重复的独立连通路线
TOCOL(...)
把最终筛选完的所有路线,全部展开成整齐单列,从上到下竖排显示,完美适配你 E 列单元格输出格式
末尾最终调用
excel
判断提取(E10)
整个 LET 公式的出口:直接传入你 E10 单元格的起点-终点查询值,全部流程跑完,输出全部完整连通路线。
四、整条公式完整递归全流程串讲
用你表格里 E10 单元格查询 红庙-繁华 完整走一遍,一眼看懂全链路:
调用 判断提取(E10)
拆分查询文本:MID(E10,1,2) 拿到起点红庙;MID(E10,4,2) 拿到终点繁华
起点红庙传入 终点循环 终极递归函数
第 1 轮:红庙 → 找下一站,得到 红庙-华隆、红庙-昆山
第 2 轮:各自继续延伸 → 红庙-华隆-合肥、红庙-昆山-芜湖
第 3 轮:继续延伸 → 红庙-华隆-合肥-繁华、红庙-华隆-合肥-横溪
第 4 轮:继续延伸 → 红庙-华隆-合肥-横溪-繁华、红庙-昆山-芜湖-繁华
全部路径走到终点、无路可走,递归停止,返回全部 4 条完整路径
动态正则筛选:.*繁华,从全部路径里,只保留末尾是繁华的全部路线
去重 + TOCOL 展开单列,最终输出:
plaintext
红庙-华隆-合肥-繁华
红庙-华隆-合肥-横溪-繁华
红庙-昆山-芜湖-繁华
和你表格 E 列预期结果完全一模一样!
五、新手必看易错点 & 公式亮点总结
正则贪婪.* 用法、非贪婪区分
正则内嵌套函数 / MID 截取:引号拼接铁则,函数绝对不能塞进双引号内部
[一-龟]中文区间、连续字符匹配基础
LET 多 Lambda 自定义函数分层管理
LAMBDA 自身递归调用、递归终止条件写法
TAKE/DROP 数组拆分、VSTACK 数组堆叠批量处理
UNIQUE+TOCOL 数组收尾规整
递归函数一定要写终止条件!你公式里终点循环的IF(下站循环(a)=a)就是终止阀,没有会无限递归公式报错
正则拼接函数,绝对不要把函数写在双引号内部,所有函数、单元格全部拉到引号外用&拼接
数组递归一定要用 VSTACK 做堆叠,不然多条路径会覆盖丢失