SPL 的序号思维及定位计算

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

1 成员访问

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

image.png

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

1555635817984100.png    1555635814064100.png

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

1555635814124100.png

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

image.png

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

1555635814064100.png   1555635814198100.png   1555635817984100.png   1555635814266100.png

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

1555635814321100.png

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

image.png

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

1555635814398100.png   1555635814266100.png   1555635814455100.png   1555635814398100.png

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

image.png

A2与A3计算结果如下:

1555635814505100.png   1555635814584100.png

2 子集访问

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

image.png

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

1555635814651100.png    1555635814708100.png    1555635814787100.png

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

1555635814868100.png

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

image.png

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

1555635814931100.png    1555635815021100.png    1555635815082100.png

 

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

image.png

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

1555635815141100.png    1555635815222100.png    1555635815303100.png

1555635815380100.png    1555635815451100.png

 

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

image.png

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

1555635815512100.png   1555635815573100.png   1555635815573100.png

1555635815644100.png   1555635815698100.png   1555635815777100.png

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

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

image.png

A2~A4结果如下:

1555635814584100.png   1555635814505100.png   1555635814505100.png   1555635814584100.png

其中,用 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结果如下:

1555635814505100.png   1555635814584100.png

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结果如下:

1555635815829100.png    1555635815896100.png

1555635815953100.png    1555635816005100.png

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

image.png

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

1555635815829100.png    1555635816062100.png    1555635816142100.png

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

1555635816197100.png   1555635816285100.png

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

image.png

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

1555635816352100.png    1555635816422100.png    1555635816493100.png

1555635816493100.png    1555635816552100.png

4 对位访问

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

image.png

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

1555635815829100.png    1555635816608100.png

1555635815896100.png    1555635815896100.png    1555635816667100.png

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

image.png

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

1555635816734100.png    1555635816790100.png

5 序列对齐

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

image.png

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

1555635816841100.png

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

1555635816936100.png

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

image.png

计算后,A4结果如下:

1555635817013100.png

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

 

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

image.png

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

1555635817072100.png

6 间隔数列

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

image.png

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

1555635817169100.png    1555635817253100.png

1555635817323100.png    1555635817388100.png

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

image.png

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

7 序号数列

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

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

image.png

A2~A5结果如下:

1555635817449100.png    1555635817530100.png

1555635817530100.png   1555635814505100.png

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

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

image.png

A2~A5的计算结果如下:

1555635817530100.png    1555635817608100.png

1555635817686100.png    1555635814505100.png

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

image.png

 

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

image.png

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

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

image.png

8 定位计算

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

image.png

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

1555635817743100.png

1555635817844100.png    1555635817903100.png

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


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31543054/viewspace-2652999/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31543054/viewspace-2652999/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值