【程序设计】5.1 [一把抓] 集合运算
5.1 集合运算
现在,我们学会了使用序列,但这个序列看起来就像之前所说的,是一批变量用了同一个名字,我们在操作这些序列成员时仍然是一个个去引用和赋值的。这一章里,我们来学习如何将序列当成一个整体来操作。
序列本质上是个集合,那么容易想到的是,应该可以支持集合相关的运算,也就是交、并等。
SPL 提供了四种集合运算符:
A |
B |
|
1 |
=[1,2,3,4,5,1] |
=[4,6,4,5,1] |
2 |
=A1|B1 |
=B1|A1 |
3 |
=A1&B1 |
=B1&A1 |
4 |
=A1^B1 |
=B1^A1 |
5 |
=A1\B1 |
=B1\A1 |
6 |
=A1|1 |
=A1&1 |
7 |
=1|B1 |
=1&B1 |
8 |
=A1\1 |
=B1\1 |
A1|B1 将序列 B1 的成员追加到序列 A1 后面形成新序列返回,这个运算称为和列。&、^、\ 则分别是通常意义的集合并、交、差运算。我们在前面用过 \ 表示整除运算,这里在序列上表示差集。
需要注意的是,和数学上的无序集合不同,序列是成员是有序的,这会导致 A1&B1 和 B1&A1 并不一定相同,SPL 中的序列交、并运算不满足交换律。有序集合还允许重复的成员,这时候再做交、并、差运算时,会比无重复成员的集合会更为复杂,请仔细观察上面的运算结果以了解这时候的运算规律。
另外,也支持序列和单值之间的运算,这相当于和只有一个成员的序列运算。单值放在运算符的左边和右边都可以。
我们用集合运算来改写水仙花数:
A |
B |
C |
D |
E |
F |
|
1 |
=0 |
=[] |
||||
2 |
for 9 |
=100*A2 |
=A2*A2*A2 |
|||
3 |
for 0,9 |
=B2+10*B3 |
=C2+B3*B3*B3 |
if C3<D3 |
break |
|
4 |
for 0,9 |
=C3+C4 |
=D3+C4*C4*C4 |
|||
5 |
if D4==E4 |
>B1=B1|D4 |
||||
6 |
else if D4<E4 |
break |
将计算出来的水仙花数用 | 运算接到当前序列后面就可以了。
帕斯卡三角:
A |
B |
C |
|
1 |
5 |
=[[1],[1,1]] |
|
2 |
for 3,A1+1 |
=[] |
|
3 |
for 2,A2-1 |
>B2=B2|[B1(A2-1)(B3-1)+B1(A2-1)(B3)] |
|
4 |
>B1=B1|[1|B2|1] |
用内循环把当前行的中间部分算出来,然后前后各拼接上 1,再整个拼到目标的二层序列后面。
序列作为一种数据,还可以进行比较:
A |
|
1 |
=[1,2,3,4]==[1,2,3,4] |
2 |
=[1,2,3,4]!=[1,3,2,4] |
3 |
=[1,2,3,4]<[1,2,4] |
4 |
=[1,2,3,4]<[1,2,3,4,5] |
这几个判断的结果都是 true。序列比较时采用常规的字典排序法。按次序依次对比每对成员,用第一对不相等的成员的大小来判断序列的大小;如果一直相等,则认为较长的序列更大;如果成员都对应相等且长度相同,则认为这两个序列相等。特别地,因为有序,成员构成相同的序列不一定是相等的。
我们前面用 [0]*n 生成一个长度为 n 的全 0 序列。SPL 还提供了 to() 函数生成由整数构成的序列。
A |
B |
|
1 |
=to(5) |
[1,2,3,4,5] |
2 |
=to(2,6) |
[2,3,4,5,6] |
3 |
=to(5,1) |
[5,4,3,2,1] |
4 |
=to(6,2) |
[6,5,4,3,2] |
A 列计算结果即等于 B 列中写的常数序列。
SPL 把这种成员都是整数的序列称为数列。
结合我们学过的循环语句,可以发现 for n、for a,b 基本相当于 for to(n)、for to(a,b),说基本相当而不是等价,是因为前两者在循环结果后的循环变量取值和后两者并不一样。
序列成员的序号也都是整数,我们可以按某数列成员指明的序号从序列中取出成员构成另一个序列。对于序列 A 和数列 p,在 SPL 中,可以用 A(p)表示 [A(p(1)),…,A(p(k))],k 是 p 的长度。A(p) 称为 A 的产生列。
A |
B |
|
1 |
=[9,8,7,6,5,4,3,2,1] |
=A1([5,2,6]) |
2 |
=A1([1,2,3,5]) |
=A1.to(5) |
3 |
=A1(to(3,7)) |
=A1.to(3,7) |
4 |
=A1(to(5,A1.len())) |
=A1.to(5,) |
5 |
=A1(A1) |
=A1(A1|to(9)) |
B1 将取出 A1 的第 5,2,6 个成员构成序列,即 [5,8,4]。对于由序列中部分连续成员构成的序列,可以用序列的 to() 函数来获得。A2、A3、A4 可以简化成 B2、B3、B4 的样子,注意 B2 和 B4 的写法,B4 中的逗号不能省略。
A5 和 B5 是个有意思的计算,请自己观察它的结果。
通常产生列会是原序列的一部分(这时候可以俗称为子序列),但数列也可能有重复成员,所以产生列并不一定总是原序列的子序列。