SPL中的集合都是有序的,可以用序号来引用成员,灵活运用序号可以使运算更为简捷高效。
1 成员访问
SPL的某些函数中可以使用序号或序号数列作为参数,最简单的应用是直接用序号访问成员,这和一般编程语言中的数组类似。
A2与A3从序列中获取指定位置的成员,位置序号是从1开始的,结果如下:
A4与A5修改了序列中的某个成员,用分步执行的方式,可以看到A1中序列的变化如下:
使用A.m(i) 函数可以从后面倒数取或循环取,这个函数为A(i) 提供了有效的补充。
A2和A3用A.m() 函数从序列中获取指定序号成员的值,其中-2表示倒数第2个成员。A4和A5中的代码添加了@r选项,在获取成员时,如果指定的序号越界则循环取数,如序号12循环A1中的成员2次后,相当于获取第2个成员。A2~A5结果如下:
A6中,指定的序号6超过了序列的长度,又没有使用@r选项,会返回空值。
SPL还提供了一组关于位置查找的函数,它们都是以p开头的,如:
A2查找指定成员的位置序号,如果有多个同值成员,只返回第1个序号。A3和A4分别返回最小与最大成员的序号。A5中,找到第1个满足设定条件的成员的序号,这里查找第1个5的倍数成员所在位置。计算后,A2~A5结果如下:
如果无法找到成员,A.pos() 函数将返回null,因此可以用A.pos()函数来判断成员是否属于集合。
A2与A3计算结果如下:
2 子集访问
用序号数列作为参数可以访问集合的子集,如:
A2,A3与A4分别从序列中获取子集,计算后,A2,A3和A4结果如下:
A5与A6修改序列中的成员,使用序数数列作为参数,一次修改多个成员。分步执行时可以看到A1中序列的改变如下:
A.m() 函数也可以使用数列参数获得子集:
在例子中,参数数列中可以使用负数表示倒数的位置,也可以添加@r选项表示位置越界回转。另外还可以使用@0选项,此时如果参数序列中存在越界的序号,则对应的空值不会出现在结果中。A2,A3和A4结果如下:
如果在位置查找函数中加上@a选项,将找到所有满足条件的成员,并用它们的序号构成数列返回:
由于添加了@a选项,此时A2会返回序列A1中所有2的位置,A3会返回值最小的所有成员的序号,A4会返回值最大的所有成员的序号,A5会返回所有2的倍数的成员的序号。使用@a选项时,即使只找到一个成员,也将返回序号的序列,而不是序号本身,如A6查找8所在的所有位置。A2~A6计算结果如下:
同时返回多个成员的位置需要用A.pos() 函数时,根据需要可能需要添加@i选项,如:
使用A.pos@i() 在查找参数序列中的成员时,会单向顺次进行;而只使用A.pos() 时只会简单判断序列A中是否包含参数序列中的每个成员。A2~A7结果如下:
可以看到,A3与A4的结果为空,其中A3计算时找不到序列中的第3个1,A4计算时无法依次找到1,2,3。或者说,A.pos@i() 只会返回递增数列,如果不能找到结果即返回null。
A.pos@i() 在有成员找不到时将返回空,但由于次序和可重复成员的因素,并不能简单地用其判断子集是否被包含,一般要用交运算:
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 循环函数定位
类似符号~,在循环函数的参数中,可以用#表示当前成员的序号。
A2获得序号构成的数列,A3获得每个位置成员与序号相加的结果序列。A4用A.select()函数在A1的序列中选出每3个中的第2个成员,即第2,5,8,…位置的成员,并构成序列。A5中将A1每2个成员分为一组。A2~A5结果如下:
在循环函数中,SPL还提供用[ ]符号以相对方式访问成员:
A2就是从序列中取出每个成员本身,A3在每个位置取出后面的1个成员,A4计算出序列中每个成员与前一个成员相比较的增长率。A2,A3和A4计算结果如下:
A5查询出指定编号的股票信息。A6计算出每日股价的涨幅,A8进一步计算出这支股票的最大连涨天数。A6和A8的结果如下:
还可以用~[a,b]在循环运算中访问子集:
A2在每个位置列出了序列中前后3个位置的成员。A3计算每个位置的移动平均值。A4和A5同样都是累计求和。A6计算反向的累计求和,即剩余成员的总和。A2~A6结果如下:
4 对位访问
我们知道,循环函数中的符号#用以表示当前成员的序号,事实上它就是个数,和其它数一样可以参加运算,特别是可以用作序号访问其它序列的成员。利用这个特点,我们可以在计算中对位访问其它序列:
在循环计算中,表达式中的#可以用来表示当前的序号。计算后,A2,A3,A5,A6和A7结果分别如下:
使用多个等长的序列时,利用对位访问可以实现出类似记录字段的效果:
A4计算总分的排名,计算总分时按照位置取得成绩。A5生成姓名与排名的序表,同样根据位置将两个序列中的数据关联起来。A4和A5结果如下: