为 Lambda 语法增加序运算能力

我们继续讨论集合运算中的 Lamba 语法,引入和次序相关的运算能力。

SQL 延用了数学上的无序集合概念,遍历集合时也不关注次序。但计算机只能一步步地执行,循环时总会有个次序,充分利用这个次序就可以方便地表达更丰富的计算需求。

比如我们想从一个集合取出半数成员构成新集合。这看起来象是过滤运算,但过滤条件和集合成员本身并没有关系,而是由循环时的次序号决定的。

SPL 中只用 ~ 写法还无法方便地描述出这种运算,这时候还需有个符号(标识符)来表示循环的次序号。这是 Lambda 语法的第四条。

事实上,大部分高级语言在写循环语句时都会有个循环变量来表示次序号,就起到了这个作用。但在 Lambda 语法中并没有提供这个机制,碰到这种运算就只能再写循环或人为造个序号序列才能完成,就显得很繁琐。SQL 也没有表示遍历次序号的方案,只能先用子查询人为制造一个序号出来再针对这个序号进行过滤。

SPL 用 #来表示遍历的次序号,那么这个运算就很容易写了:

复制代码
A.select(#<=A.len()/2)		取前一半成员
A.select(#%2==0)		取偶数位置的成员

对应地,在过滤运算中一般总是返回满足条件的成员,但有时候我们并不关心具体成员而只关心成员的次序号,SPL 中还设计返回次序号的过滤函数:

复制代码
A.pselect( ~>5 )		返回大于5的成员的次序号

类似地,还可能有:

复制代码
A.pmax()			返回最大值的次序号
...

关于这些位置相关的运算,我们以后还会专门讲。

考虑到集合上遍历的次序时,我们还可以进一步丰富计算的描述能力。

比如有 12 个月的销售额数据已经按次序准备好,要计算哪些月份的增长率超过了 5%。

SQL 写这种跨行计算比较麻烦,需要用 JOIN 或窗口函数把上月数据和本月数据对齐,然后再来计算增长率,这不可避免地用到子查询。

如果提供了相邻成员的引用语法,就可以很容易描述这个计算了。

SPL 中用 i 表示和当前成员距离为 i 的成员,再结合前述的 #写法,上面的计算就可以写成:

复制代码
A.(if(~/~[-1]>1.05,#,0)).select(~>0)

~-1 表示前一个成员,也就是上月销售额。找出把增长率超过 5% 的月份(也就是 #),其它月份清 0,最后选出这些非 0 的月份。

如果用上述的返回次序号的过滤函数,还可以写成更简单的形式:

复制代码
A.pselect(~/~[-1]>1.05)

除了相邻成员外,还可能有相邻集合的引用,比如还是上面的集合,我们希望计算前后各一个月的销售额移动平均值。

SPL 把 i 表达式扩展成 a,b 写法来表示相邻成员构成的集合,这个运算就很容易描述了:

复制代码
A.(~[-1,1].avg())

相邻集合还可能有更复杂的情况,比如计算到当月的累积销售额。

SPL 允许 a,b 写法中 a 缺省表示从第一个成员开始(对等地,b 缺省可以理解为最后一个成员),这个运算可以写成

复制代码
A.(~[,0].sum())

同样的,面向结构化数据计算也还可以直接使用字段名,如果例子中的集合是由"月份"和"销售额"的两个字段构成的表,则上述的运算可以分别写成:

复制代码
A.select(amount/amount[-1]>1.05)			这里结果集中已有月份字段,不再需要用#了
A.derive(amount[-1,1].avg:move_average)			增加一个字段表示移动平均
A.derive(amount[,0].sum():cum_amount)

考虑到有序性时,Lambda 语法的规则就比常规集合运算要复杂一些,而这些有序运算是经常发生的,如果 Lambda 语法不支持,会导致这些计算难以描述,程序员就要再退回到编写多行循环语句的状态,或者人为造出序号,繁琐且影响可读性。

SQL 没有提供有序的 Lambda 语法,经常需要使用子查询和窗口函数来生成序号,某些复杂些的有序遍历运算甚至写不出来,也要用存储过程手段转换成多行循环语句才可以。从这个意义讲,SQL 虽然有集合化特性,但集合化不够彻底。

Python 提供了局部的序号能力,相邻引用也比较麻烦。SPL 可能是唯一提供较完整有序 Lambda 语法的语言。

开源SPL源码地址

免费下载试用

相关推荐
IT_陈寒28 分钟前
Python闭包里藏的这个坑,差点让我加班到凌晨
前端·人工智能·后端
IT_陈寒28 分钟前
Java注解空指针?这个坑我踩得莫名其妙
前端·人工智能·后端
JAVA社区30 分钟前
Java高级全套教程(十一)—— Kubernetes 超详细企业级实战详解
java·运维·微服务·容器·面试·kubernetes
H0r1zon.42 分钟前
PinCopy:双击 Ctrl,把剪贴板「钉」在屏幕上
前端
8Qi81 小时前
LeetCode 23. 合并 K 个升序链表 —— 小顶堆(PriorityQueue)
数据结构·算法·leetcode·链表·
tedcloud1231 小时前
cc-switch评测:多AI Coding Agent管理工具详解
数据库·人工智能·sql·学习·自动化
kyriewen1 小时前
大厂面试新规:不会用AI编程,直接挂
前端·面试·ai编程
QiLinkOS1 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
土狗TuGou1 小时前
SQL内功笔记 · 第8篇:事务的四大特性与隔离级别
数据库·笔记·后端·sql·mysql·oracle
努力找实习的前端小白1 小时前
useImperativeHandle,useRef,forwardRef的协作关系
前端·面试