bac0id's Blog

J语言笔记

24 Feb 2024

J语言是一种阵列、隐式、反射式、函数式的编程语言,属APL语言家族。它在数学和统计学程序设计上十分高效。

参考资料

[1] Alvord L, Thomson N. Easy-J[M/OL]. 2002. https://www.jsoftware.com/books/pdf/easyj.pdf

[2] 郭平欣. J語言初步[M/OL]. http://faculty.ndhu.edu.tw/~pkuo/computer/Jyuyen.pdf

[3] Iverson E. J Primer[M/OL]. 2001. https://www.jsoftware.com/help/primer/contents.htm

[4] Stokes R. Learning J. An Introduction to the J Programming Language[M/OL]. 2015. https://www.jsoftware.com/help/learning/contents.htm

[5] J Wiki. NuVoc[Z/OL]. 2024. https://code.jsoftware.com/wiki/NuVoc

[6] Foreign Conjunction[Z/OL]. https://www.jsoftware.com/help/dictionary/xmain.htm

入门

运算1

4+6%2		NB. 输出如下。4+(6÷2)。
7		NB. J语言中四则运算没有优先级,只是从右到左依次完成,但加括号的除外。
		NB. 牛逼NB.表示注释。

4%6+2		NB. 输出如下。4÷(6+2)。
0.5

4^3		NB. 输出如下。4的3次方。
64

1+2%3		NB. 输出如下。
1.66667

(1+2)%3		NB. 输出如下。
1

3-8		NB. 输出如下。负数用前导下划线_表示负号。
_5

3-_8		NB. 输出如下。
11

赋值

value1=._1.6	NB. 令value1为-1.6
value1		NB. 输出_1.6

c=.3 1 4 0.5 _2	NB. 令c是向量[3, 1, 4, 0.5, -2]
d=.4 0 3 _1.2 7

运算2

c+d		NB. 7 1 7 _0.7 5 两个向量中每个位置上的元素对应做运算。
c*d		NB. 12 0 12 _0.6 _14
d%c		NB. 1.333 0 0.75 _2.4 _3.5
d%c		NB. 0.75 _ 1.333 _0.4167 _0.2857
		NB. 除以0时,结果是infinity,用_表示。

c+1 2 3		NB. 报错。向量做运算前保证元素数量符合要求。
|length error
| c     +1 2 3	NB. 在有错误的地方,会用一些空格,标记出来。
		NB. C语言的编译错误提示类似~~^~~~~


%:c		NB. 1.732 1 2 0.7071 0j1.414。向量c的每个元素的平方根。
		NB. 注意到0j1.414是虚数。


^.c		NB. 自然对数
1.099 0 1.386 _0.6931 0.6931j3.142

10^.c		NB. 以10为底的对数
0.4771 0 0.6021 _0.301 0.301j1.364

2^.1 2 4 8 20	NB. 以2为底的对数
0 1 2 3 4.322

数组操作1

#c		NB. 输出5。数组长度为5。别忘记c为[3, 1, 4, 0.5, -2]。
2+#c		NB. 输出7。2+数组长度5。
3{c		NB. 输出0.5。c的第3个元素。
0 3 4{c		NB. 输出3 0.5 _2。c的第0,3,4个元素。

cv=.'J is useful.'	NB. 字符串用''表示
cv			NB. 输出J is useful.
#cv			NB. 输出12。字符串长度是12。
0 7 10 10 2 7 3{cv	NB. 输出Jellies

#_3.875			NB. 输出1。

J词汇1

符号#是一种J词汇。J词汇有一元(monadic)和二元(dyadic)之分。J词汇的左右两边的东西叫左参数和右参数(left/right arguments)。

3#c			NB. 输出3 3 3 1 1 1 4 4 4 0.5 0.5 0.5 _2 _2 _2。符号#作为二元词汇时,称为copy。即将[右参数]的各项复制[左参数]次。

matrix=.3 4$c		NB. 输出如下。符号$作为二元词汇时,称为reshape。以下效果是wrapping round
3 1 4 0.5
_2 3 1 4
0.5 _2 3 1

$matrix			NB. 输出如下。符号$作为二元词汇时,称为shape。
3 4
#matrix			NB. 输出如下。符号#仅计算最顶层元素数量。
3

数组操作2

b=.4
c+b		NB. c的各元素+b。别忘了c是[3, 1, 4, 0.5, -2]。
7 5 8 4.5 2

c*2		NB. c的各元素*2。
6 2 8 1 _4

c,b		NB. c和b合并。符号,表示追加(append)。
3 1 4 0.5 _2 4

J词汇2

+z=.4+6%2	NB. 输出7。符号+表示conjugate。这样可同时赋值和显示数值。
		NB. 词典:conjugate v.(根据数、人称、时态等)列举(动词)的变化形式;   (表示数、人称、时态等)有词形变化形式;adj.成对的;结合的;【化,数,物】共轭的;【语】同源[根]的。


*b		NB. 输出1。符号*表示signum,即符号函数。
*-b		NB. 输出_1。符号-表示negate。
*b-b		NB. 输出0。

%b		NB. 输出0.25。符号%表示倒数(reciprocal)。别忘了b是4。

+value1=.1.6	NB. 输出1.6。
>.value1	NB. 输出2。符号>.表示上取整。
<.value1	NB. 输出1。符号<.表示下取整。
b>.value1	NB. 输出4。符号>.表示取二者的较大值。max(b,value1)
b<.value1	NB. 输出1.6。符号<.表示取二者的较大值。min(b,value1)

c>.d		NB. 输出如下。求两个向量对应位置上的较大元素。
4 1 4 0.5 7

0>.d		NB. 输出如下。将d中小于0的元素替换为0。别忘了d是[4,0,3,_1.2,7]
4 0 3 0 7

J词汇3

例:求1 foot 4½ inches分别占了2 feet, 2 ft. 6 ins., 3 ft., 6 ft., and 10 ft.中的多少百分比。Suppose you want to express 1 foot 4½ inches as a percentage of first 2 feet, then 2 ft. 6 ins., 3 ft., 6 ft., and 10 ft., in each case rounding the answer to the nearest percentage above. Using a list allows all five calculations to be done in parallel:

>.100*(1+4.5%12)%2 2.5 3 6 10
69 55 46 23 14

例:在1650年在银行存入12元。假设利率分别是3%, 4%, 5%, 10%,按复利计算,则到了2000年本金和利息有多少钱?An Indian is said to have sold Manhattan Island to white settlers in 1650 for 12 dollars. What would be the dollar value of this sum in the year 2000 if invested at compound interest of 3%, 4%, 5%, 10%?

(9!:11)16	NB. 设置print precision为16
<.12*(1+0.03 0.04 0.05 0.1)^(2000-1650)
373430 10986263 312921872 3686557834057256

例:某物体进行自由落体运动,经过1,2,4,8,16秒后,它下落的高度是多少?在该瞬间,它的速度是多少?

+h=.0.5*9.81*1 2 4 8 16^2
4.905 19.62 78.48 313.92 1255.68
+v=.%:2*9.81*h
9.81 19.62 39.24 78.48 156.96

J词汇4

|c		NB. 输出如下。符号|表示取各元素的绝对值。
3 1 4 0.5 2

1.6|b		NB. 输出如下。符号|表示取模(residue)。4除以1.6余0.8。
0.8


a=.1 2 3 4
+/a		NB. 输出10。符号/表示“在每个元素之间应用指定符号”。此行展开为1+2+3+4。
-/a		NB. 输出_2。展开为1-2-3-4。别忘了算式是从右到左执行的,即1-(2-(3-4))
*/a		NB. 输出24。展开为1*2*3*4。
%/a		NB. 输出0.375。展开为1%2%3%4,即1%(2%(3%4))
>./a		NB. 输出4。即max(1,2,3,4)。别忘了x>.y表示取二者较大值。
<./a		NB. 输出1。即min(1,2,4,4)

J词汇5

比较运算:小于<、小于等于<:、大于>、大于等于>:、等于=、不等于~:

c<d		NB. 输出如下。别忘了c是[3, 1, 4, 0.5, -2],
1 0 0 0 1	NB. d是[4, 0, 3, _1.2, 7]

(c<d)#c		NB. 输出如下。符号#表示计件复制(copy),把左参数中是1的位置,对应右参数中的元素位置,将右参数中的元素复制出来。
3 _2		NB. 此例求得“c中哪些元素小于d中对应位置的元素?”

(c>:d)#c	NB. 输出如下。此例求得“c中哪些元素大于等于d中对应位置的元素?”
1 4 0.5

6 e. c		NB. 输出0。符号e.表示membership。即“6在c中吗?”

c e. b		NB. 输出如下。c中的各元素在b中吗?别忘了c是[3, 1, 4, 0.5, -2],
0 0 1 0 0

c e. d		NB. 输出如下。c中的各元素在d中吗?别忘了d是[4, 0, 3, _1.2, 7]
1 0 1 0 0

J词汇6

逻辑运算:与*.、或+.、非-.、与非*:、或非+:

0 1 1*.1 1 0	NB. 输出如下。
0 1 0

-.c<d		NB. 输出如下。上一节中第一个例子的取反。
0 1 1 1 0

+./0 1 0 1 0	NB. 输出如下。改写成C语言,为 0|1|0|1|0=1
1

J词汇7

i.6		NB. 输出如下。符号i.表示index generator。产生从0开始递增的整数数列。
0 1 2 3 4 5

i._6		NB. 输出如下。若右参数是负数,则是递减的数列。
5 4 3 2 1 0

i.0		NB. 输出空,因为是空列表。
#i.0		NB. 输出0。
$i.0		NB. 输出0。
$b		NB. 输出空,注意:数字的shape是空数组。别忘了b是4。
#b		NB. 输出1,数字的元素个数是1。

+/i.0		NB. 输出0。连加器的初始值是0。
*/i.0		NB. 输出1。连乘器的初始值是1。

_4+i.9		NB. 输出如下。善用偏移量。
_4 _3 _2 _1 0 1 2 3 4

3+0.5*i.13	NB. 输出如下。改变步长。
3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9

(97+i.26){a.	NB. 输出如下。所有ASCII字符都收录在符号a.中。别忘了符号{表示选取指定下标的元素。
abcdefghijklmnopqrstuvwxyz

J词汇7

k=.1 2 3 4 5
k+/k	NB. 输出如下。符号/作为二元词汇时表示tables。
 2  3  4  5  6
 3  4  5  6  7
 4  5  6  7  8
 5  6  7  8  9
 6  7  8  9 10

k*/k	NB. 输出如下。
 1  2  3  4  5
 2  4  6  8 10	NB. 即2*1 2*2 2*3 2*4 2*5
 3  6  9 12 15
 4  8 12 16 20
 5 10 15 20 25

(k*/k){(96+i.26){a.	NB. 输出如下。
abcde
bdfhj
cfilo
dhlpt
ejoty

c e.b		NB. 输出如下。c中的哪些元素在b(=4)中?别忘了c是[3, 1, 4, 0.5, -2],
0 0 1 0 0

c i.b		NB. 输出如下。符号i.表示求指定元素的下标(index of)。b是c中的第几个元素?
2

d i.c		NB. 输出如下。d中的各元素分别是c中的第几个元素?d[0]=c[2]=4,d[2]=c[0]=3
2 5 0 5 5	NB. 注意:输出的3个5都表示not found。

J词汇8

3{.c		NB. 输出如下。符号{.表示take,取前/后[左参数]个元素。取前3个元素。注意:3{c则是取第3个元素。
3 1 4

_3{.c		NB. 输出如下。如果[左参数]是负数,则是取后[左参数]个元素。取后3个元素。
4 0.5 _2

3}.c		NB. 输出如下。符号}.表示drop,删前/后[左参数]个元素。删前3个元素。
0.5 _2

_3}.c		NB. 输出如下。删后3个元素。
3 1

{.c		NB. 符号{.作为一元词汇时,取第0个元素。
}.c		NB. 符号}.作为一元词汇时,删第0个元素。
{:c		NB. 符号{:表示取最后1个元素(tail)。
}:c		NB. 符号{:表示删最后1个元素。

模拟

?6		NB. 符号?表示roll,产生[0,6)中的随机整数。

b=.>:a=.?6	NB. 符号>:表示加1(increment),符号<:表示减1(decrement)
		NB. a是个随机数,而b比a大1。

>:?6 6 6 6 6 6 6 6 6 6	NB. 产生10个[1,6]中的随机整数。

?10#5		NB. 产生10个[0,5)区间的随机整数。别忘了从右到左的执行顺序。


NB. 例:统计1000个新生儿的性别。0是女,1是男。
+/?1000#2	NB. 别忘了符号/表示“连续相同运算”。

10?10		NB. 符号?表示deal,产生10个[0,10)范围的不重复随机整数。也就是[0,9]的一种打乱、乱序。
5?10		NB. 产生5个[0,10)范围内的不重复随机整数。


NB. 例:发扑克牌。
+hand=.13?52
43 50 25 45 40 4 9 11 24 42 17 19 37

,suits=.(<.hand%13){'CDHS'		NB. 符号,表示ravel???
SSDSSCCCDSDDH

,values=.(13|hand){'23456789TJQKA'
6KA836JKK568K

values,:suits				NB. 符号,:表示按行合并数组。
6KA836JKK568K
SSDSSCCCDSDDH

NB. 例:杨辉三角。(https://en.wikipedia.org/wiki/Pascal%27s_triangle)
(i.8)!/i.8		NB. 符号!表示组合数,x!y是从y中选x的组合数。
1  1  1  1  1  1  1  1
0  1  2  3  4  5  6  7
0  0  1  3  6 10 15 21
0  0  0  1  4 10 20 35
0  0  0  0  1  5 15 35
0  0  0  0  0  1  6 21
0  0  0  0  0  0  1  7
0  0  0  0  0  0  0  1

自定义J词汇

(>./-<./)c	NB. 输出6。求c的最大值与最小值之差。3个连续的J词汇组成了叉子(fork)

range=.>./-<./	NB. 定义J词汇range是求最大值与最小值之差。
range c		NB. 输出6。“调用”这个J词汇。

定义 range 时,不需要指定数据类型,由此可见,J 语言是隐式编程(tacit programming)。以下是其他例子。

mean=.+/%#	NB. 定义mean是求平均值。2个连续的J词汇组成了钩子(hook)。解释:+/是求和,%是除法,#是求数组长度。
mean c		NB. 输出1.3

mdev=.-mean	NB. 定义mdev是求各元素与平均值之差。
mdev c		NB. 输出1.7 _0.3 2.7 _0.8 _3.3
hook
一元:  (u v) y ↔ y u (v y)
二元:x (u v) y ↔ x u (v y)

fork
一元:  (f g h) y ↔ (f y) g (h y)
二元:x (f g h) y ↔ (x f y) g (x h y)

@:
一元:  (u @: v) y ↔ u (v y)
二元:x (u @: v) y ↔ u (x v y)

@
一元:  (u @ v) y ↔ (u @: v)"v y
二元:x (u @ v) y ↔ x (u @: v)"v y

把二元动词变为一元动词:

add=.{.+}.	NB. 解释:({.1 2)+(}.1 2)
add 1 2		NB. 输出3
]data=.2 3 4 $i.24
 0  1  2  3
 4  5  6  7
 8  9 10 11

12 13 14 15
16 17 18 19
20 21 22 23

NB. 秩 3 加總同於不限制秩的加總,為 2 個 3x4 表單之和,仍為 3x4 的表單。
+/"3 data
12 14 16 18
20 22 24 26
28 30 32 34

NB. 秩 2 加總為分別對各表單的成員做加總,故得到 2x4 的表單。
+/"2 data
12 15 18 21
48 51 54 57

NB. 秩 1 加總為分別對各條列的成員做加總,故得到 2x3 的表單。
+/"1 data
 6 22 38
54 70 86

NB. 秩 0 加總對各單一元素分別做加總動作,故得到原來的 2x3x4 陣列。

算术平均数 $ \frac {\sum_{i=1}^{n}x_i}{n} $

mean=. +/ % #

几何平均数 $ \sqrt[n]{\prod_{i=1}^{n}x_i} $

geomean=. # %: */

调和平均数 $ \frac {n}{\sum_{i=1}^{n}{\frac{1}{x_{i}}}} $

harmean=. # % +/ @: %

频数

freq_count=. +/"1 @ (=/)

x=. 1 1 2 2 2 3 4 4 5 5 5 5 6
echo 1 2 3 4 5 6 freq_count x
NB. 输出 2 3 1 2 4 1

: 同时定义一元和二元动词

minus =. 3 : 0
- y
:
x - y
)

3 minus 5
_2
5 minus 3
2
minus 5
_5

Rank conjunction “

Refer from https://www.jsoftware.com/help/primer/rank_conjunction.htm .

The primitive “ (double-quote, not two quotes) is the rank conjunction. Conjunctions haven’t been introduced yet and there is more detail in a later section. For now, just think of a conjunction as similar to a dyad verb in that it takes a left and right argument and has a result. The particular use of “ of interest here is when the left argument is a verb and the right argument is a noun. Yes, conjunctions can take verb arguments, as well as noun, whereas a verb can take only noun arguments.

The rank conjunction produces a new verb from its left argument with the rank information from its right argument.

   plus000 =. + " 0 0 0

**The first 0 is the rank of the monad argument. The second and third 0’s are respectively the rank of the dyad left and right arguments. **

   plus011 =. + " 0 1 1
   a plus011 1 2 3
1 3 5
4 6 8
   1 2 3 plus011 a
1 3 5
4 6 8

   a =. i. 2 3
   1 2 3 +" 0 1 1 a
1 3 5
4 6 8

Since + is applied dyadically and both ranks are 1, you can use the shorter form of +”1 which uses 1 for the rank of all arguments.

   1 2 3 +"1 a
1 3 5
4 6 8

In this case, the left frame is empty with a cell shape of 3 and the right frame is 2 with a cell shape of 3. Empty is a prefix of 2, and so the frames agree.

There is one thing you have to be aware of.

   a +"1 1 2 3
|length error
|   a    +"1 1 2 3

The problem is that J doesn’t know that you want the first 1 to be the argument to “ and the second 1 to be part of the constant 1 2 3. What happens is that the constant 1 1 2 3 is used as the right argument of “ and since “ is defined to allow only arguments of 1 2 or 3 numbers, there is a length error. You need to let J know that the 1 belongs to the “ and that the 1 2 3 is a constant.

   a (+"1) 1 2 3
1 3 5
4 6 8
   a +"1 (1 2 3)
1 3 5
4 6 8

Result shape

Refer from https://www.jsoftware.com/help/primer/result_shape.htm .

Consider the verb $ . Look it up in the J Dictionary and you’ll see it has rank of _ 1 _ . The _ indicates an infinite (unbounded) rank and means that the verb applies to the entire argument. The monad has unbounded rank and so applies to the entire right argument. If you think about the monad $ with a result that is the shape of its entire right argument this makes sense. The dyad left rank is 1 and this means that it applies to lists from the left argument. The dyad right rank is unbounded and so applies to the entire right argument.

   2 4 $ i.3
0 1 2 0
1 2 0 1
   2 4 $"1 0 i.3
0 0 0 0
0 0 0 0

1 1 1 1
1 1 1 1

2 2 2 2
2 2 2 2

The first example is what you have seen before, but what is going on in the second? The $"1 0 means that $ will get cell arguments as a list (1-cells) on the left and as an atom (0-cell) on the right. The left frame is empty (nothing is left of the shape of the left argument after a 1-cell is taken) and the right frame is 3 (there are 3 0-cells in the right argument). So the result frame is 3.