SPL 的序号思维及定位计算

浏览: 1101

SPL中的集合都是有序的,可以用序号来引用成员,灵活运用序号可以使运算更为简捷高效。

1 成员访问

SPL的某些函数中可以使用序号或序号数列作为参数,最简单的应用是直接用序号访问成员,这和一般编程语言中的数组类似。

image.png

A2与A3从序列中获取指定位置的成员,位置序号是从1开始的,结果如下:

 

A4与A5修改了序列中的某个成员,用分步执行的方式,可以看到A1中序列的变化如下:

使用A.m(i) 函数可以从后面倒数取或循环取,这个函数为A(i) 提供了有效的补充。

image.png

A2和A3用A.m() 函数从序列中获取指定序号成员的值,其中-2表示倒数第2个成员。A4和A5中的代码添加了@r选项,在获取成员时,如果指定的序号越界则循环取数,如序号12循环A1中的成员2次后,相当于获取第2个成员。A2~A5结果如下:

A6中,指定的序号6超过了序列的长度,又没有使用@r选项,会返回空值。

SPL还提供了一组关于位置查找的函数,它们都是以p开头的,如:

image.png

A2查找指定成员的位置序号,如果有多个同值成员,只返回第1个序号。A3和A4分别返回最小与最大成员的序号。A5中,找到第1个满足设定条件的成员的序号,这里查找第1个5的倍数成员所在位置。计算后,A2~A5结果如下:

如果无法找到成员,A.pos() 函数将返回null,因此可以用A.pos()函数来判断成员是否属于集合。

image.png

A2与A3计算结果如下:

2 子集访问

用序号数列作为参数可以访问集合的子集,如:

image.png

A2,A3与A4分别从序列中获取子集,计算后,A2,A3和A4结果如下:

   

A5与A6修改序列中的成员,使用序数数列作为参数,一次修改多个成员。分步执行时可以看到A1中序列的改变如下:

A.m() 函数也可以使用数列参数获得子集:

image.png

在例子中,参数数列中可以使用负数表示倒数的位置,也可以添加@r选项表示位置越界回转。另外还可以使用@0选项,此时如果参数序列中存在越界的序号,则对应的空值不会出现在结果中。A2,A3和A4结果如下:

  

 

如果在位置查找函数中加上@a选项,将找到所有满足条件的成员,并用它们的序号构成数列返回:

image.png

由于添加了@a选项,此时A2会返回序列A1中所有2的位置,A3会返回值最小的所有成员的序号,A4会返回值最大的所有成员的序号,A5会返回所有2的倍数的成员的序号。使用@a选项时,即使只找到一个成员,也将返回序号的序列,而不是序号本身,如A6查找8所在的所有位置。A2~A6计算结果如下:

   

 

 

同时返回多个成员的位置需要用A.pos() 函数时,根据需要可能需要添加@i选项,如:

image.png

使用A.pos@i() 在查找参数序列中的成员时,会单向顺次进行;而只使用A.pos() 时只会简单判断序列A中是否包含参数序列中的每个成员。A2~A7结果如下:

可以看到,A3与A4的结果为空,其中A3计算时找不到序列中的第3个1,A4计算时无法依次找到1,2,3。或者说,A.pos@i() 只会返回递增数列,如果不能找到结果即返回null。

A.pos@i() 在有成员找不到时将返回空,但由于次序和可重复成员的因素,并不能简单地用其判断子集是否被包含,一般要用交运算:

image.png

A2~A4结果如下:

其中,用A.pos@i(B) 查找判断时,如果结果非空,说明在A中可以依次找到B中的成员,说明A必然包含B。但是如果查找结果是null,只能说明在A中无法依次找到B中的成员,并不能说明A必然不包含B,比如A3中的情况。

A.pos(B) 查找判断时,如果结果为空,说明B中一定有成员是无法在A中找到的,说明A必然不包含B。但是,如果此时查找的结果不为空,如果B中存在重复的成员,那么是无法保证A包含B的,如A5中的情况。

A8与A9结果如下:

B^A==B来判断A是否包含B是可行的,根据A8和A9中的结果,可以确定A1包含A6,但A1不包含A7。使用这种方法时需要注意,交运算的操作数不能反过来,否则计算A^B得到的结果中成员的顺序有可能与B不同,就无法正确判断了。

3 循环函数定位

类似符号~,在循环函数的参数中,可以用#表示当前成员的序号。

image.png

A2获得序号构成的数列,A3获得每个位置成员与序号相加的结果序列。A4用A.select()函数在A1的序列中选出每3个中的第2个成员,即第2,5,8,…位置的成员,并构成序列。A5中将A1每2个成员分为一组。A2~A5结果如下:

 

 

在循环函数中,SPL还提供用[ ]符号以相对方式访问成员:

image.png

A2就是从序列中取出每个成员本身,A3在每个位置取出后面的1个成员,A4计算出序列中每个成员与前一个成员相比较的增长率。A2,A3和A4计算结果如下:

   

A5查询出指定编号的股票信息。A6计算出每日股价的涨幅,A8进一步计算出这支股票的最大连涨天数。A6和A8的结果如下:

还可以用~[a,b]在循环运算中访问子集:

image.png

A2在每个位置列出了序列中前后3个位置的成员。A3计算每个位置的移动平均值。A4和A5同样都是累计求和。A6计算反向的累计求和,即剩余成员的总和。A2~A6结果如下:

  

 

4 对位访问

我们知道,循环函数中的符号#用以表示当前成员的序号,事实上它就是个数,和其它数一样可以参加运算,特别是可以用作序号访问其它序列的成员。利用这个特点,我们可以在计算中对位访问其它序列:

image.png

在循环计算中,表达式中的#可以用来表示当前的序号。计算后,A2,A3,A5,A6和A7结果分别如下:

 

   

使用多个等长的序列时,利用对位访问可以实现出类似记录字段的效果:

image.png

A4计算总分的排名,计算总分时按照位置取得成绩。A5生成姓名与排名的序表,同样根据位置将两个序列中的数据关联起来。A4和A5结果如下:

 

5 序列对齐

利用对位访问之前需要确保各序列已经按同一次序排好,但实际应用时序列未必总是这样,这时使用对齐函数A.align() 即可令序列按某个基准序列重新排序:

image.png

A2和A3的序表均已按A1中的员工编号对齐,A4计算出员工的工资序表如下:

A6将数据按照A5序表中运动员的名字对齐,A7据此计算出加权成绩。A8再计算出加权分的排名后,最终A9整理出结果序表如下:

事实上,使用@a选项的对齐函数也会返回一个与基准序列对齐的序列,只是其每个成员都是集合,同样可以应用对位访问。

image.png

计算后,A4结果如下:

无选项A.align() 函数将对应基准序列的每个成员,在源序列中取出第1个成员再构成集合返回,而不是返回集合的集合,当事先明确知道每个分组子集只有1个成员时,使用A.align()函数即相当于完成了一次按基准序列排序的运算。

 

类似地,枚举分组也可以对位访问,只是A.enum() 中@1选项是无效的,只能处理分组式问题:

image.png

A5计算出3个年龄组中员工总数如下:

6 间隔数列

数列是一种特殊的集合,它本身是个集合,可以应用各种集合运算,同时,它又可以作为序号用于访问其它序列的子集,灵活运用数列是建立序号思维的重要环节,如:

image.png

to() 函数可以得到由连续的整数构成的序列,而step() 函数则可以设定数列成员的间隔等参数,A1~A4结果依次如下:

 

 

使用子序列在原序列中的位置数列可以用来处理子集,如:

image.png

在上面的例子中,可以用数列来为原序列赋值,也可以获取子序列等。

7 序号数列

如果对序列排序,那会丧失成员的原有次序信息,但有时这个信息还要用,比如我们想知道年龄最大的三名员工在全公司的入职次序,某支股票股价最高的三个交易日的涨幅,…。

为此,SPL提供了A.psort() 函数,用以返回排序后成员在排序前的序号。

image.png

A2~A5结果如下:

 

通俗地说,在A.psort() 返回的数列中,第1个数是本次排序应当排在第1位的成员在原序列的序号,第2个数是应当排在第2位的成员在原序列的序号,…。

用序号数列产生的序列,也可以用A.inv() 函数获得序号数列的逆数列,来进行回复操作,如:

image.png

A2~A5的计算结果如下:

 

 

有了A.psort()和A.inv() 两个函数,就可以很方便地解决需要保持原序号的问题:

image.png

 

在查找数据时,使用二分法能够极大地提高效率,但这种方法要求原序列对于查找的关键字有序,若原序列无序则需要先排序。如果是查找成员本身,先排序没有问题,但要查找成员的序号时,排序则会破坏这个信息,这时又需要使用A.psort() 函数,如:

image.png

这里用A.psort() 相当于为序列建立了一个二分法查找索引,一个序列可以同时按不同关键字建立多个查找索引。

对齐分组函数也可以返回序号构成的数列而不直接返回对齐后的序列,如:

image.png

8 定位计算

计算出了所需记录的序号,就可以用定位计算A.calc() 来计算所需结果。使用定位计算可以避免不必要的计算,从而提高计算效率。

image.png

A2,A4和A5中的计算结果如下:

 

在这个例子中,二进制文件VoteRecord中存储了某次投票的结果,并已经按票数降序排序。A4计算出指定州的员工编号序列。A5根据编号序列,计算出这些员工还需获得多少票,排名就可以上升。如目前排在第3位的Ryan Williams,需要再获得69票,排名就可前进1位。在计算中需要跨行处理,这种计算不能仅根据选出员工的数据完成,还需要原表中的相关数据。

推荐 0
本文由 润乾软件 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册