5 构建阵列(Arrays)
这是对<
Learning J>(by Roger Stokes)的尝试翻译。
Roger Stokes的版权声明如下:
Copyright © Roger Stokes 2012. This material may be freely reproduced, provided that this copyright notice is also reproduced.
感谢作者的无私奉献,请您转载时也注明以上版权,也请同时注明转载地址
http://corwindong.blogspot.com,我将不胜感激。
----------------------------------------------------------------------------------
本章的主题是构建阵列。首先考察如何从列表构建阵列,然后学习一些将阵列拼接在一起构成更大阵列的方法。
5.1 通过给列表塑形来构建阵列
5.1.1 回顾
回忆一下第2章中“元素”的含义。数字列表中的元素就是数字本身。表格的元素就是表格的每行。三维阵列的元素就是阵列的每个平面。
再回想一下,x $ y 生成一个以x为形状,y的元素为元素的阵列。也就是说,阵列的维度有列表x给出。例如:
2 2 $ 0 1 2 3 | 2 3 $ 'ABCDEF' |
0 1 2 3 | ABC DEF |
如果y的元素数比维度表要求的少,那么将会循环使用y直到元素数满足要求。例如:
2 3 $ 'ABCD' | 2 2 $ 1 | 3 3 $ 1 0 0 0 |
ABC DAB | 1 1 1 1 | 1 0 0 0 1 0 0 0 1 |
动词“塑形”,也就是二元模式 $,有相应的一元模式——“求形”,一元模式的$返回阵列的维数列表(也就是阵列的形状)。比如:
A =: 2 3 $ 'ABCDEF' | $ A | a =: 'pqr' | $ a |
ABC DEF | 2 3 | pqr | 3 |
对于任何阵列A,它的维度表($ A)是一个一维列表(阵列的形状)。因此$ $ A是一个只包含一个元素(阵列的秩),$ $ $ A是一个值包含数字1的列表。
A | $ A | $ $ A | $ $ $ A |
ABC DEF | 2 3 | 2 | 1 |
5.1.2 空阵列
阵列的每个维数都可以为0。一个长度为0的空列表可以通过以0作为维数表来构建,任何值都可以作为空列表的值。
如果E为空,那么E没有任何元素,在它后面追加一个元素后,结果将得到含有一个元素的列表。
类似的,如果ET是一个0行3列的空列表,当增加一行时,结果将得到1行3列的表格。
ET =: 0 3 $ 'x' | $ ET | $ ET , 'pqr' |
| 0 3 | 1 3 |
5.1.3 构造一个标量
假如我们要构造一个标量。标量没有维度,它的维度表为空。我们可以通过以空列表作为 $ 的左参数来构造标量:
S =: (0$0) $ 17 | $ S | $ $ S |
17 | | 0 |
5.1.4 广义塑形
我们知道,(x $ y)生成一个以x为形,y的元素为元素的阵列。那就是说,在广义上讲,(x$y)的形状不仅仅由x决定,而是由x和y的元素的形状共同决定。如果y是一个表格,那么y的元素就是行(一个列表)。在下面的例子中,Y的元素的形状是Y的行长度,也就是4。
X =: 2 | Y =: 3 4 $ 'A' | Z =: X $ Y | $ Z |
2 | AAAA AAAA AAAA | AAAA AAAA | 2 4 |
下一节我们将学习如何从连接已有阵列来构造新阵列。
5.2 追加,或者首尾相连
回忆一下,阵列可以看作是元素的列表,所以一张表格的元素就是它的行。动词
,(逗号)叫做“追加”。表达式 (x, y) 是一个由x和y的元素组成的列表,y的元素和x的元素首尾相接。
B =: 2 3 $ 'UVWXYZ'
b =: 3 $ 'uvw'
a | b | a , b | A | B | A , B |
pqr | uvw | pqruvw | ABC DEF | UVW XYZ | ABC DEF UVW XYZ |
在上例的 (A, B) 中,A的元素是长度为3的列表,B的元素也是一样。因此A和B的元素兼容,也就是说,有着相同的秩和长度。如果它们不兼容会怎么样?在这种情况下“追加”动词将自动尝试延长某个参数去适应另一个,通过使它们有相同的秩,填充长度,需要时重复使用标量等方式。下面的例子将展示这些方法。
5.2.1 使秩相同
假如我们要把一行追加到表格后面。例如,要把3个字符的列表b(上面那个b)追加到2x3的表格A(上面的A)后面,形成一个新行。
A | b | A , b |
ABC DEF | uvw | ABC DEF uvw |
注意,我们想要在有两个元素的A后面追加有一个元素的b,但是b不是只有一个元素。我们通过将b重塑形成一个1x3的表格来达到目的,就是说,通过提升b的秩来完成。但是,这不是必须的,因为,正如我们看到的,动词“追加”自动地提升了低秩的参数,使之成为一个单元素阵列——通过提供首维度1 来完成。
A | b | A , (1 3 $ b) | A , b | b , A |
ABC DEF | uvw | ABC DEF uvw | ABC DEF uvw | uvw ABC DEF |
5.2.2 填充长度
当一个参数的元素比另一个参数少时,将会用填充来增加长度。字符阵列用空字符填充,数值阵列用0填充。
A | A , 'XY' | (2 3 $ 1) , 9 9 |
ABC DEF | ABC DEF XY | 1 1 1 1 1 1 9 9 0 |
5.2.3 重复标量
动词“追加”的标量参数需要时会被重复使用以匹配另一个参数。下面的例子中,注意标量 '*' 是如何重复,而向量 (1 $ '*') 是如何填充的。
A | A , '*' | A , 1 $ '*' |
ABC DEF | ABC DEF *** | ABC DEF * |
5.3 缝合,或者并排连接
二元动词
,.(逗号 点)叫做“缝合”。表达式(x ,. y)中,x中的每个元素和y中相应的元素相连,形成结果中的一个元素。
a | b | a ,. b | A | B | A ,. B |
pqr | uvw | pu qv rw | ABC DEF | UVW XYZ | ABCUVW DEFXYZ |
5.4 叠层,或者面对面连接
动词
,:(逗号 冒号)称为“叠层”。(x ,: y)的结果将永远是一个有两个元素的阵列,第一个元素是x,第二个是y。
如果x和y都是表格,我们可以想象结果是一个表格叠在另一个上面,形成一个3维阵列,第一维的长度为2.
A | B | A ,: B | $ A ,: B |
ABC DEF | UVW XYZ | ABC DEF
UVW XYZ | 2 2 3 |
5.5 拼接
动词
;(分号)称为“拼接”。它可以方便地构建盒子列表。
'good' ; 'morning' | 5 ; 12 ; 1995 |
+----+-------+ |good|morning| +----+-------+ | +-+--+----+ |5|12|1995| +-+--+----+ |
注意示例 5;12;1995 展示了 (x;y) 并不仅仅总是(< x), (< y)。既然“拼接”用来构建盒子列表,当它的右参数已经是盒子列表时,它能分辨出来。如果我们定义一个动词来生成(< x) , (<y):
foo =: 4 : '(< x) , (< y)'
我们可以比较一下二者的区别:
1 ; 2 ; 3 | 1 foo 2 foo 3 |
+-+-+-+ |1|2|3| +-+-+-+ | +-+-----+ |1|+-+-+| | ||2|3|| | |+-+-+| +-+-----+ |
5.6 解构阵列
我们已经看到了四个二元动词:“追加”(,),“缝合”(,.),“叠层”(,:)和“拼接”(;)。它们每一个都有一元模式,下面我们来看看。
5.6.1 推平
一元
; 叫做“推平”。它将参数的元素拆盒后组装成列表。
B =: 2 2 $ 1;2;3;4 | ; B | $ ; B |
+-+-+ |1|2| +-+-+ |3|4| +-+-+ | 1 2 3 4 | 4 |
5.6.2 散开
一元
, 叫做“散开”。它将参数的元素组装成列表。
B | , B | $ , B |
+-+-+ |1|2| +-+-+ |3|4| +-+-+ | +-+-+-+-+ |1|2|3|4| +-+-+-+-+ | 4 |
5.6.3 散开元素
一元模式
,. 叫做“散开元素”。它将参数的每个元素散开后组装成表格。
k =: 2 2 3 $ i. 12 | ,. k |
0 1 2 3 4 5
6 7 8 9 10 11 | 0 1 2 3 4 5 6 7 8 9 10 11 |
“散开元素”在通过列表构造单列表格时很有用。
5.6.4 元素化
一元 ,: 称为“元素化”。它将任何阵列构造成一个单元素阵列,通过提供首维度1来完成。
A | ,: A | $ ,: A |
ABC DEF | ABC DEF | 1 2 3 |
5.7 阵列:大和小
我们已经看到过,一个阵列可以通过动词$来构造。
3 2 $ 1 2 3 4 5 6
1 2
3 4
5 6
对于小的阵列——阵列的内容可以在一行列出来——也有替代$的方法,这些方法可以不需要提供维度。
> 1 2 ; 3 4 ; 5 6 | 1 2 , 3 4 ,: 5 6 |
1 2 3 4 5 6 | 1 2 3 4 5 6 |
构建大型表格,下面有一个方便的方法。首先,有一个“实用”动词(一个对我们的目标有帮助的动词,但是我们现在不需要研究它的定义)。
ArrayMaker =: ". ;. _2
ArrayMaker的目的是通过脚本来逐行地构造数值表格。
table =: ArrayMaker 0 : 0
1 2 3
4 5 6
7 8 9
)
table | $ table |
1 2 3 4 5 6 7 8 9 | 3 3 |
(ArrayMaker的工作原理,请参考第17章)。盒子阵列也可以用同样的方式从脚本输入:
X =: ArrayMaker 0 : 0
'hello' ; 1 2 3 ; 8
'Waldo' ; 4 5 6 ; 9
)
X | $ X |
+-----+-----+-+ |hello|1 2 3|8| +-----+-----+-+ |Waldo|4 5 6|9| +-----+-----+-+ | 2 3 |
第5章就到这里。
说明:
- Array在APL系语言中,个人感觉翻译成阵列比数组更贴切一些。