2012年11月15日星期四

5 构建阵列(Arrays)

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 32 3 $ 'ABCDEF'
0 1
2 3
ABC
DEF


如果y的元素数比维度表要求的少,那么将会循环使用y直到元素数满足要求。例如:
2 3 $ 'ABCD'2 2 $ 13 3 $ 1 0 0 0
ABC
DAB
1 1
1 1
1 0 0
0 1 0
0 0 1


动词“塑形”,也就是二元模式 $,有相应的一元模式——“求形”,一元模式的$返回阵列的维数列表(也就是阵列的形状)。比如:
A =: 2 3 $ 'ABCDEF'$ Aa =: 'pqr'$ a
ABC
DEF
2 3pqr3


对于任何阵列A,它的维度表($ A)是一个一维列表(阵列的形状)。因此$ $ A是一个只包含一个元素(阵列的秩),$ $ $ A是一个值包含数字1的列表。
A$ A$ $ A$ $ $ A
ABC
DEF
2 321



5.1.2 空阵列

阵列的每个维数都可以为0。一个长度为0的空列表可以通过以0作为维数表来构建,任何值都可以作为空列表的值。
E =: 0 $ 99$ E
0

如果E为空,那么E没有任何元素,在它后面追加一个元素后,结果将得到含有一个元素的列表。
E$ Ew =: E ,98$ w
0981


类似的,如果ET是一个0行3列的空列表,当增加一行时,结果将得到1行3列的表格。
ET =: 0 3 $ 'x'$ ET$ ET , 'pqr'
0 31 3



5.1.3 构造一个标量

假如我们要构造一个标量。标量没有维度,它的维度表为空。我们可以通过以空列表作为 $ 的左参数来构造标量:
S =: (0$0) $ 17$ S$ $ S
170



5.1.4 广义塑形

我们知道,(x $ y)生成一个以x为形,y的元素为元素的阵列。那就是说,在广义上讲,(x$y)的形状不仅仅由x决定,而是由x和y的元素的形状共同决定。如果y是一个表格,那么y的元素就是行(一个列表)。在下面的例子中,Y的元素的形状是Y的行长度,也就是4。
X =: 2Y =: 3 4 $ 'A'Z =: X $ Y$ Z
2AAAA
AAAA
AAAA
AAAA
AAAA
2 4
下一节我们将学习如何从连接已有阵列来构造新阵列。

5.2 追加,或者首尾相连

回忆一下,阵列可以看作是元素的列表,所以一张表格的元素就是它的行。动词 ,(逗号)叫做“追加”。表达式 (x, y) 是一个由x和y的元素组成的列表,y的元素和x的元素首尾相接。
   B =: 2 3 $ 'UVWXYZ'
   b =:   3 $ 'uvw'
   
aba , bABA , B
pqruvwpqruvwABC
DEF
UVW
XYZ
ABC
DEF
UVW
XYZ


在上例的 (A, B) 中,A的元素是长度为3的列表,B的元素也是一样。因此A和B的元素兼容,也就是说,有着相同的秩和长度。如果它们不兼容会怎么样?在这种情况下“追加”动词将自动尝试延长某个参数去适应另一个,通过使它们有相同的秩,填充长度,需要时重复使用标量等方式。下面的例子将展示这些方法。

5.2.1 使秩相同

假如我们要把一行追加到表格后面。例如,要把3个字符的列表b(上面那个b)追加到2x3的表格A(上面的A)后面,形成一个新行。

AbA , b
ABC
DEF
uvwABC
DEF
uvw


注意,我们想要在有两个元素的A后面追加有一个元素的b,但是b不是只有一个元素。我们通过将b重塑形成一个1x3的表格来达到目的,就是说,通过提升b的秩来完成。但是,这不是必须的,因为,正如我们看到的,动词“追加”自动地提升了低秩的参数,使之成为一个单元素阵列——通过提供首维度1 来完成。

AbA , (1 3 $ b)A , bb , A
ABC
DEF
uvwABC
DEF
uvw
ABC
DEF
uvw
uvw
ABC
DEF


5.2.2 填充长度

当一个参数的元素比另一个参数少时,将会用填充来增加长度。字符阵列用空字符填充,数值阵列用0填充。

AA , 'XY'(2 3 $ 1) , 9 9
ABC
DEF
ABC
DEF
XY
1 1 1
1 1 1
9 9 0


5.2.3 重复标量

动词“追加”的标量参数需要时会被重复使用以匹配另一个参数。下面的例子中,注意标量 '*' 是如何重复,而向量 (1 $ '*') 是如何填充的。
AA , '*'A , 1 $ '*'
ABC
DEF
ABC
DEF
***
ABC
DEF
*


5.3 缝合,或者并排连接

二元动词 ,.(逗号 点)叫做“缝合”。表达式(x ,. y)中,x中的每个元素和y中相应的元素相连,形成结果中的一个元素。

aba ,. bABA ,. B
pqruvwpu
qv
rw
ABC
DEF
UVW
XYZ
ABCUVW
DEFXYZ


5.4 叠层,或者面对面连接

动词 ,:(逗号 冒号)称为“叠层”。(x ,: y)的结果将永远是一个有两个元素的阵列,第一个元素是x,第二个是y。
aba ,: b
pqruvwpqr
uvw


如果x和y都是表格,我们可以想象结果是一个表格叠在另一个上面,形成一个3维阵列,第一维的长度为2.
ABA ,: 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 ; 31 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 44


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


“散开元素”在通过列表构造单列表格时很有用。

b,. b
uvwu
v
w


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 61 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章就到这里。

说明:
  1. Array在APL系语言中,个人感觉翻译成阵列数组更贴切一些。

没有评论:

发表评论