最近在Excel答疑交流群里,有位负责销售数据统计的朋友问到了一个日常工作中非常典型且棘手的问题:他手里的商品销售流水表,每款商品对应的所有销售记录都挤在同一个单元格内,用逗号分隔成“姓名+销量”的混排格式,少则三四条、多则几十条记录都堆在一格里。现在需要针对每一款商品,提取出每位销售员的单次最高销售记录,最终还要以“姓名+最高销量”的格式合并输出到C列对应单元格。(为方便演示,数据源已做简化处理)
放在以往,处理这类非结构化的混排文本数据,往往要经过分列、逐行拆分、补全对应关系、数据透视表分组聚合等好几步的辅助列操作,源数据一更新就得全部返工。而随着WPS表格新版本中Groupby、Byrow、Regexp等动态数组新函数的全面普及,这类原本要花费十几分钟甚至几十分钟处理的场景,如今只靠一条嵌套公式就能实现全自动计算,不仅逻辑清晰、易于调整,后续数据更新也能自动同步结果,实实在在的把非结构化文本统计的效率提升了好几个档次。
用正则提取中文姓名、数字,并输出一行数组:
=REGEXP(B2,"[一-龟]+|\d+")
Regexp对B2文本扫描,把所有姓名、数字全部拆出来,忽略逗号等分隔符号。{"张华","15","李丽","10","张华","25","李丽","15"}这一步最终的目标就是把逗号隔开的混合字符串,拆成交替出现的:“姓名,数字,姓名,数字......” 的一行多列的数组。用WrapRows函数将单行数组转为两列多行数组:
=WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2)
WrapRows(...,2)
单行或单列的数组,每2个元素换行。
按每行2个元素,重组成2列多行的数组。
此时,原来交替出现的一行多列的数组元素,转为“姓名+销量”两列的结构化表格,方便后续分组。
注意:此时第二列销量还是文本型数字。因为Regexp正则函数提取出来的数字默认是以文本格式存储的。
把上一步生成的数组,命名为变量a。避免重复写一大串表达式,后面直接用a引用这个数组,简化公式,提升计算效率。
a=
WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2)
Let内部变量赋值:
=LET(a,WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2),调用a参与计算)
第三参数:后续计算表达式,可以直接使用变量a,执行后续的业务逻辑。调用a使用Groupby函数分组求最大值:
=LET(a,WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2),GROUPBY(TAKE(a,,1),TAKE(a,,-1)*1,MAX,0,0))
取数组a的第1整列,也就是全部姓名列:{"张华";"李丽";"张华";"李丽"}取数组a的最后1列(即第2列销量文本),“*1”是把文本数字{"15";"10";"25";"15"} 强制转换成真正的数值:{15;10;25;15}Groupby(分组依据列,待聚合列,聚合函数,[是否显示标头],[是否显示总计行])Groupby按姓名分组,求出每个人单次最高销量,得到“姓名+该人最大销量”的汇总结果。
这一步本质上就实现了:人名去重保留唯一值,并显示每人的最大销量。
调用a使用Bycol函数:
=LET(a,WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2),BYROW(GROUPBY(TAKE(a,,1),TAKE(a,,-1)*1,MAX,0,0),CONCAT))
Byrow(数组,Lambda(单行,处理逻辑))将上一步Groupby输出的2行2列的数组用Byrow逐行遍历,每一行都重复执行Concat拼接本行单元格内容。第1行Concat({"张华",25}),文本合并后:“张华25”第2行Concat({"李丽",15}),文本合并后:“李丽15”得到一个一维的竖向数组:{"张华25";"李丽15"}最终把分组后的“姓名+最大数字”每行拼接成“姓名+数字”的文本字符串:调用a使用ArrayToText函数:
=LET(a,WRAPROWS(REGEXP(B2,"[一-龟]+|\d+"),2),ARRAYTOTEXT(BYROW(GROUPBY(TAKE(a,,1),TAKE(a,,-1)*1,MAX,0,0),CONCAT)))
ArrayToText(数组)把竖向文本数组,转为一个单元格内的逗号分隔字符串。上一步多行的数组结果,被压缩成一个单元格内用逗号间隔的完整文本:最后一步,我们可以选择使用下拉填充公式法,得到B2:B3(或更多)所有需要处理的单元格的目标结果。
下拉填充公式:
也可以利用Byrow或Map对B2:B3区域需要处理的数据进行逐个遍历。
Byrow法:
=BYROW(B2:B3,LAMBDA(x,LET(a,WRAPROWS(REGEXP(x,"[一-龟]+|\d+"),2),ARRAYTOTEXT(BYROW(GROUPBY(TAKE(a,,1),TAKE(a,,-1)*1,MAX,0,0),CONCAT)))))
太基础,不做过多讲解:
Byrow(B2:B3,Lambda(x,...))
Map法:
=MAP(B2:B3,LAMBDA(x,LET(a,WRAPROWS(REGEXP(x,"[一-龟]+|\d+"),2),ARRAYTOTEXT(BYROW(GROUPBY(TAKE(a,,1),TAKE(a,,-1)*1,MAX,0,0),CONCAT)))))
同样太基础,不做过多讲解:
Map(B2:B3,Lambda(x,...))
(如果您觉得本文对自己有所启发,希望点一个“推荐”鼓励小编;如果您还有其它方面的问题,可后台消息框回复“提问”进行咨询)
学习Excel/你可以不常用/但不能不会用/如果你没有天赋/那就一直重复/当你快到本能反应的时候/你的重复就是别人眼中的天赋/冲破捆绑/展翅翱翔