为 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源码地址

免费下载试用

相关推荐
王解2 分钟前
Vue CLI 脚手架创建项目流程详解 (2)
前端·javascript·vue.js
刘大浪6 分钟前
vue.js滑动到顶便锁定位置
前端·javascript·vue.js
qystca10 分钟前
洛谷 P1595 信封问题 C语言dp
算法
Yhame.11 分钟前
Java 集合框架中的 List、ArrayList 和 泛型 实例
java
coding侠客11 分钟前
Spring Boot 多数据源解决方案:dynamic-datasource-spring-boot-starter 的奥秘
java·spring boot·后端
小金刚®12 分钟前
构建简洁之美:我的第一个前端页面
前端
明矾java17 分钟前
Mysql-SQL执行流程解析
数据库·sql·mysql
委婉待续17 分钟前
java抽奖系统(八)
java·开发语言·状态模式
芳菲菲其弥章27 分钟前
数据结构经典算法总复习(下卷)
数据结构·算法
我是一只来自东方的鸭.40 分钟前
1. K11504 天平[Not so Mobile,UVa839]
数据结构·b树·算法