资讯专栏INFORMATION COLUMN

6. Q语言学习之路—函数

Jensen / 2087人阅读

摘要:接下来几章将进入语言的核心内容函数表数据转换查询和等等,函数说明在中,函数是可以修改全局变量的,所以并不是一个纯正的函数式语言。函数体内最大的局部变量个数为个。当执行操作时,当前项是函数的左运算元,前一项是函数的右运算元。

接下来几章将进入Q语言的核心内容——函数、表、数据转换、查询和I/O等等, excited :)

1. 函数说明

在q中,函数是可以修改全局变量的,所以q并不是一个纯正的函数式语言。
1. 函数定义
使用花括号{},函数的输入输出类型不用指定,甚至函数名都可以不用指定。如下是一个完整的函数定义:

q) {[x] x*x}

调用函数时,参数用中括号包围起来,参数通过分号;分隔

q){[x] x*x}[3]
9

函数可以赋值给一个变量:

q)f:{[x] x*x}
q)f[3]
9

2. 函数标识和术语
函数的正式定义为{[p1;...;pn] e1; ...; em},其中可选的p1;...;pn是正式的参数,e1; ...; em是执行的表达式,虽然是从左向右写的,但是仍然是从右向左执行的。

函数的参数个数被称为函数的valence, 最常见的函数是monadic(valence 1)dyadic(valence 2)

一个niladic函数是指一个没有输入的函数,表示如下:

f:{[] … }

例子如下:

q){[] 42} / pure function returns constant 42
42
q){[] a*a} / impure function: references global a
{[] a*a}

函数最大的参数个数(valence)为8,超过8个参数将会报错。如果参数较多的话,将参数打包成list或者dictionary输入函数。

函数的输出值为函数最后一个表达式的结果:

q){[x] x*x}
q){[x;y] a:x*x; b:y*y; r:a+b; r}
Keep it short. 很多q语言中的函数都是紧凑并且模块化的,很多函数都是仅仅一行

3. 函数应用
函数的调用是严格的,意味着在参数替换之前,表达式就已经被执行了:

q)f:{[x] x*x}
q)f[0N!3+1]
4
16

当提供的参数多于函数定义的参数时,会报"rank错误。

q) {[x] x*x}[3;4]
"rank

4. 没有返回值的函数
函数体最后只有一个分号;,返回::

q)fvoid:{[x] `a set x;}
q)fvoid 42
q)a
42

注意在q中,分号;分隔符而并不是终止符

5. 参数的并列写法
类似于列表索引和字典取值,函数的参数也可以是并列写法:

q){[x] 2*x} 42
84
q)f:{[x] x*x}
q)f 5
25

6. 函数名的应用
当函数被赋值给一个全局变量时,可以通过symbol形式的函数名来调用:

q)f:{x*x}
q)f[5]
25
q)`f[5]
25
q)`f 5
25
q).my.name.space.f:{2*x}
q)`.my.name.space.f[5]
10

7. 隐含的参数
当一个函数没有参数被明确定义时,三个隐含的参数x, y, z会被自动定义,下面的函数定义是等价的:

{[x] x*x}
{x*x}
{[x;y] x+y}
{x+y}

三个参数x, y, z的调用是按照先后顺序的,意味着x总是第一个被调用,y第二个,z第三个。下面这个函数只有提供三个参数值时才会返回值

q)g:{x+z}  / likely meant x+y; requires 3 args in call
q)g[1;2]   / still waiting for 3rd arg – i.e., a projection
{x+z}[1;2]
q)g[1;2;3] / 2nd arg is required but ignored
4

8. 匿名函数和lambda表达式
一个没有函数名称的函数叫做匿名函数,匿名函数的常见的两个用处:

定义在函数内的匿名函数

f{[...] ...; {...}[...]; ...}

函数容器

q)powers:({1}; {x}; {x*x}; {x*x*x})
…
q)selected:2
q)powers[selected]
{x*x}

9. 恒等函数::
恒等函数::返回它的输入作为输出;裸的恒等函数不能使用并列的形式,它必须使用中括号调用。

q)::[42]
42
q)::[`a`b`c]
`a`b`c
q):: 42 / error
"
q)(::) 42
42

10. 函数是数据
类似于python中的函数是对象一样,在q语言中函数都是数据,可以作为输入和输出。

q)apply:{x y}
q)sq:{x*x}
q)apply[sq; 5]
25
2. 通过名字调用

常规的函数使用传值调用(call-by-value),意味着参数在被传递时是按值传递的,在这个过程中,原始值被拷贝了一份,以保证之前的原始数据不会被修改。但这样做的一个问题是,当输入参数的size非常大时,拷贝是被禁止的。这个时候就有一个新的方法:call-by-name,在这种情况下变量的名字被传递而不是变量的值。

Call-by-name没有特别的语法。一个例子就是内置函数get,传递全局变量的名字,返回对应的值

q)a:42
q)get `a
42

另一个例子是函数set,是给全局变量赋值

q)`a set 43
`a
q)a
43
3. 局部和全局变量

1. 定义局部和全局变量
在函数体内使用:定义的变量被称为局部变量。函数体内最大的局部变量个数为24个

q)f:{a:42; a+x}

q语言不遵循词法作用域规则,意味着在函数体内的函数并没有获得上层函数体内变量的权限,例如下例中, helper函数并没有获取局部变量a的值的权限

q)f:{[p1] a:42; helper:{[p2] a*p2}; helper p1}

然而,你必须对该局部函数声明一个额外的参数来传递局部变量

q)f:{[p1] a:42; helper:{[a; p2] a*p2}[a;]; helper p1}
q)f 5
210

在所有函数定义以外的变量被称为全局变量。

2. 在函数内对全局变量赋值
当函数体内没有同名的局部变量时,可以使用双冒号::来对全局变量进行赋值;
`q)b:6
q)f:{b::7; x*b}
q)f[6]
42
q)b
7`
而当函数体内有同名的局部变量时,双冒号符操作的是局部变量,并不是全局变量

q)b:6
q)f:{b:42; b::x; b}
q)f[98]
98
q)b
6

相比::更推荐使用set来进行全局变量修改, 这样就不会有局部变量名冲突了。

q)a:42
q)f:{a:98.6; `a set x}
q)f 43
`a
q)a
43
4. 投影

投影是指只指定函数的一部分参数,其结果会是其余参数的函数。

1. 函数投影
一个函数投影的例子为:

q)add:{x+y}
q)add[42;]
{x+y}[42;]

q)add[42;][3]
45
q)add3:{x+y+z}
q)add3[2][3][4]
9

上式可以理解为add3作用于参数2,返回一个函数;该函数作用于参数3,返回一个函数;最后作用于4,返回结果9。上式等价于add3[2;3;4]

No second look. 被赋值的函数投影变量不会随着原函数的改变而改变
q)f:{x-y}
q)g:f[42;]
q)g
{x-y}[42;]
q)g[6]
36
q)f:{x+y}
q)g
{x-y}[42;]
q)g[6]
36

2. 运算符投影
当使用运算符中缀形式的时候,一个q的运算符可以通过固定其左运算元来进行投影,这时需要括号。

q)(7*) 6
42

由于任何操作符都是一个函数,当然可以使用其前缀形式进行投影:

q)-[;42] 98
56

上面两个公式中的空格符都不是必须的:

q)(7*)6
42
q)-[;42]98
56

3. 多维投影
当函数有多个参数的时候(valence > 2),函数可以有多个投影,例如下例

q){x+y+z}[1;;3]
{x+y+z}[1;;3]
q){x+y+z}[1;;3] 2
6
5. Atomic函数

一个Atomic函数是指该函数直接作用于一个q数据结构中的atom数据。

1. Monadic Atomic函数和map
回忆一下,monadic函数是指只作用于一个参数的函数,如下是一个monadic atomic函数的例子,该函数作用于一个字典

q)neg 10
-10
q)neg 10 20 30
-10 -20 -30
q)neg (10 20 30; 40 50)
-10 -20 -30
-40 -50
q)neg `a`b`c!10 20 30
a| -10
b| -20
c| -30
q)neg `a`b`c!(10 20; 30 40 50; 60)
a| -10 -20
b| -30 -40 -50
c| -60

2. Dyadic atomic函数和zip
Dyadic函数是指作用于两个参数的函数。若将dyadic函数的非atomic部分固定下来(可以看成一个函数的投影),那么dyadic函数就变为monadic函数。如下例中的dyadic操作符?

q)10 20 30?10
0
q)10 20 30?10 20 30 40 50
0 1 2 3 3
q)(enlist 10)?10
0
q)10 20?10
0
q)10 20 30 40 50?10
0

在算术中,比较和关系运算符都是atomic的,在这种应用下会有四种情况:

atom和atom

atom和list

list和atom

list和list

在最后一种情况下,两个list元素的长度必须相等

q)1+10
11
q)1+10 20 30
11 21 31
q)1 2 3+10
11 12 13
q)1 2 3+10 20 30
11 22 33

这个功能相当于传统语言中的zip

3. 构造atomic函数
简单想一想就可以明白,由atomic函数构成的函数仍然是atomic的,因此构造一个atomic函数的方法就是去包含内置的atomic函数。

构造Monadic atomic函数:

q)f:{(x*x)+(2*x)-1}
q)f 0
-1
q)f til 10
-1 2 7 14 23 34 47 62 79 98

构造Dyadic atomic函数:

q)pyth:{sqrt (x*x)+y*y}
q)pyth[1; 1]
1.414214
q)pyth[1; 1 2 3]
1.414214 2.236068 3.162278
q)pyth[1 2 3; 1 2 3]
1.414214 2.828427 4.242641
6. 副词

副词是高阶的函数,用以改变函数在列表上的应用方式。这个术语来自于将q操作符当做动词。

Proficiency in the use of adverbs is one skill that separates q pretenders from q contenders. :)

1. Monadic each
合并函数例如count只会作用在嵌套列表的最高层级:

q)count 10 20 30
3
q)count (10 20 30; 40 50)
2

如果我们想知道嵌套列表中每个元素的长度,这个时候副词each就派上用场了,它使得monadic函数能够作用于列表的每个元素而不是整个列表,each有两种使用方法:

中缀形式:each紧跟在函数的后面

q) count each (10 20 30; 40 50)
3 2

前缀形式

q) each[count] (10 20 30; 40 50)
3 2

对于层数较深的嵌套矩阵,可能需要对each进行迭代

q)(count each) each ((1 2 3; 3 4); (100 200; 300 400 500))
3 2
2 3
q)each[each[count]] ((1 2 3; 3 4); (100 200; 300 400 500))
3 2
2 3

一些例子:

q)reverse "live"
"evil"
q)reverse ("life"; "the"; "universe"; "and"; "everything")
q)reverse each ("life"; "the"; "universe"; "and"; "everything")

当想要将一个长度为n的向量转换为一个大小为n*1的矩阵时,可以使用enlist each来实现,但flip enlist在大列表上执行更快。

q)enlist each 1001 1002 1004 1003
1001
1002
1004
1003
q)flip enlist 1001 1002 1004 1003
1001
1002
1004
1003

2. each-both"
副词each-both符号"作用在一个dyadic函数上,使得函数能够成对地作用在对应的列表元素上,符号"读作"zip"

q)("abc"; "uv"),"("de"; "xyz")
"abcde"
"uvxyz"
q)1,"10 20 30
1 10
1 20
1 30
q)1 2 3,"10
1 10
2 10
3 10
q)2#"("abcde"; "fgh"; "ijklm")
"ab"
"fg"
"ij"

当熟练的时候,可以使用each-both的前缀形式:

q),"[("abc"; "uv"); ("de"; "xyz")]
"abcde"
"uvxyz"

一个table的例子:

q)t1:([] c1:1 2 3)
q)t2:([] c2:`a`b`c)
q)t1,"t2
c1 c2
-----
1  a
2  b
3  c

3. each-left :
each-left操作符作用于一个dyadic函数,使第一个参数下的每一项都应用于第二个参数:

("abc"; "de"; enlist "f") ,: ">"
"abc>"
"de>"
"f>"

4. each-right /:
each-right 作用于一个dyadic函数,使第一项作用于第二个参数的每一项:

q)"

5. Cross Product
叉积(Cross Product)成对地作用于左侧的每一项和右侧的每一项。 如果我们对join执行each-righteach-left操作,再内置函数raze对得到的嵌套矩阵夷平,就可以得到我们想要的结果

q)1 2 3,/::10 20
1 10 1 20
2 10 2 20
3 10 3 20
q)raze 1 2 3,/::10 20
1 10
1 20
2 10
2 20
3 10
3 20

上述操作还是较为复杂,我们可以通过内置函数cross来得到上述结果

q)1 2 3 cross 10 20
1 10
1 20
2 10
2 20
3 10
3 20

可以注意到,若我们组合each-lefteach-right时,我们便可以得到上述结果的转置

q)raze 1 2 3,:/:10 20
1 10
2 10
3 10
1 20
2 20
3 20

6. Over /
Over操作符/是一个提供递归机制的高阶函数。它最简单的形式是修改一个dyadic函数,使其在一个list上累积函数作用的结果

q)0 +/ 1 2 3 4 5 6 7 8 9 10
55

注意: 在运算符和/之间不能存在空格,因为/可以被用作注释。

运算符左运算元为累积计算的初始值,右运算元为待累积计算的列表。

但我们也可以省略左运算元(即初始值),这个时候需要我们对表达式做一些变换,被作用函数和Over运算符/括号包住,这时右边列表的第一个元素就是初始值。

q)(+/) 1 2 3 4 5 6 7 8 9 10
55

上面的括号是必需项,被修改的函数实际上是一个monadic函数。

一些有用的over形式:

q)(*/) 1 2 3 4 5 6 7 8 9 10 / product
3628800
q)(|/) 7 8 4 3 10 2 1 9 5 6 / maximum
10
q)(&/) 7 8 4 3 10 2 1 9 5 6 / minimum
1

使用,/可以高效地移除列表的顶层嵌套,其对应的内置函数为raze

q)(,/)((1 2 3; 4 5); (100 200; 300 400 500))
1 2 3
4 5
100 200
300 400 500
q)raze ((1 2 3; 4 5); (100 200; 300 400 500))
1 2 3
4 5
100 200
300 400 500

7. Iteration
/的另一种用法是作为循环代码的等价形式。在这个版本下,左运算元表示了循环的次数,右运算元为初始值。例如,计算Fibonacci数列:

q)fib:{x, sum -2#x}
q)10 fib/ 1 1
1 1 2 3 5 8 13 21 34 55 89 144
q)fib/[10;1 1]
1 1 2 3 5 8 13 21 34 55 89 144

另一个版本的/控制了循环的进行直至收敛,或者检测到一个环的存在。下面以牛顿法为例介绍这种循环的使用,我们使用牛顿法来寻找函数{-2+x*x}的根:

q)f:{-2+x*x}
q)secant:{[f;x;e] (f[x+e]-f x-e)%2*e}
q){x-f[x]%secant[f; x; 1e-6]}/[1.5]
1.414214

q语言会判断当前的输出值与之前的输出值之间的大小,如果两个值之间相差在一定的tolerance以内,则认为算法收敛并且迭代完成;否则继续执行循环任务。

此外,q语言通过每次比较运算结果和初始值是否match(~)来判断当前程序是否存在环(loop),如果存在环,程序则终止:

q)newtcycle:{[xn] xn-((xn*xn*xn)+(-2*xn)+2)%-2+3*xn*xn}
q)newtcycle/[0.0]
1f

如果运算的结果与初始值相等,但是类型不同(not match),程序则不会停止;例如上例中如果提供初始值0,则程序会一直运行下去。

运算符/的最后一种重载用法,等价于使用while循环,它提供了一个判断条件,若每次的运算结果满足条件,则继续执行;否则,终止计算

q)fib:{x,sum -2#x}
q)fib/[{1000>last x}; 1 1]
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

8. Scan
Scan操作符同样是一个高阶函数,其作用与操作符/一样,与其不同的是,Scan会返回中间的计算结果。可以把Scan当做是Over/的"running"版本。

q)0+1 2 3 4 5 6 7 8 9 10
1 3 6 10 15 21 28 36 45 55

q)(*)1 2 3 4 5 6 7 8 9 10

q)(|)7 8 4 3 10 2 1 9 5 6
7 8 8 8 10 10 10 10 10 10

q)(&)7 8 4 3 10 2 1 9 5 6
7 7 4 3 3 2 1 1 1 1

q)100 f1 2 3 4 5 6 7 8 9 10

q)(f)1 2 3 4 5 6 7 8 9 10

所有over操作符/的用法都适用于Scan操作符,使用Scan操作符的好处是可以看到函数中间过程的运行结果。

q)fib:{x, sum -2#x}
q)fib[{1000>last x}; 1 1]

9. each-previous ":
each-previous操作符对列表的每项和其前一项执行dyadic函数操作。当执行Dyadic操作时,当前项是Dyadic函数的左运算元,前一项是Dyadic函数的右运算元。

由于列表中第一项没有前项,所以我们必须在运算符:"左运算元的位置提供初始值,如下例

q)100 -": 100 99 101 102 101
0 -1 2 1 -1

与其它副词一样,each-previous :"也有一个monadic函数的形式。但在这种形式下,列表中的第一个元素不会被当做初始的前项,相反,它直接返回该项。

q)(-":)100 99 101 102 101
100 -1 2 1 -1
q)deltas 100 99 101 102 101
100 -1 2 1 -1
q)(%":)100 99 101 102 101
100 0.98999999999999999 1.0202020202020201 1.0099009900990099 0.99019607843137258
q)ratios 100 99 101 102 101
100 0.98999999999999999 1.0202020202020201 1.0099009900990099 0.99019607843137258

保留第一项的动机是,可以通过保留的第一项来恢复整个list

q)sums deltas 100 99 101 102 101
100 99 101 102 101
q)deltas sums 100 99 101 102 101
100 99 101 102 101

当我们需要返回的结果中都是变化值时,可以通过如下方法得到

q)deltas0:{first[x] -": x}
q)deltas0 100 99 101 102 101
0 -1 2 1 -1

一个使用each-previous的非常有用的工具是使用~判断连续项是否是match的。实际中,我们经常会关注两个连续项不同的情况,这种情况下使用内置函数differ

q)(~":) 1 1 1 2 2 3 4 5 5 5 6 6
011010001101b
q)not (~":) 1 1 1 2 2 3 4 5 5 5 6 6
100101110010b
q)differ 1 1 1 2 2 3 4 5 5 5 6 6
100101110010b

可以对differ的结果使用wherecut来分隔列表

q)L:1 1 1 2 2 3 4 5 5 5 6 6
q)where differ L
0 3 5 6 7 10
q)(where differ L) cut L
1 1 1
2 2
,3
,4
5 5 5
6 6

下面我们来做一些q的练习

q)runs:(where differ L) cut L / store runs
q)ct:count each runs / store count of each run
q)runs where ct=max ct / find the runs of maximum length
1 1 1
5 5 5

用一行代码来实现上面的代码

q) runs where ct=max ct:count each runs:(where differ L) cut L

同样,我们可以上述技术来找到上升和下降子序列

q)L:9 8 7 11 10 12 13
q)(where -0W>":L) cut L
9 8 7
11 10
,12
,13
q)(where 0W<":L) cut L
,9
,8
7 11
10 12 13
8. 一般应用
Thorough understanding of the general application is another test that separates the q pretenders from the contenders.

1. 动词 @
q语言的基础操作包括:从list中通过索引取值,在字典中通过键取值或执行一个monadic函数。
高阶函数@是q语言中基础操作的真正形式,它将一个monadic映射(可能是索引取值,字典取值或者monadic函数)作用于一个元素之上。与所有的内置函数一样,它同样有中缀和前缀的表示形式

q)10 20 30 40@1
20
q)L:10 20 30 40
q)L@1
20
q)@[L; 1]
20
q)count@L
4
q)@[count; L]
4
q){x*x}@L
100 300 900 1600
q)d:`a`b`c!10 20 30
q)d@`a
10
q)@[d;`b]
20

@niladic函数应用时,可以使用空元素::来代表空值

q)f:{6*7}
q)f[]
42
q)@[f; ::]
42
q)f@(::)
42
q)f@43
42

2. 动词.
q语言中,多元映射包括了:深度索引一个列表,从一个字典中取一个被嵌套的值和执行一个带有多个参数的函数等。高阶函数.是q语言中多元应用的真正形式。它将多元映射投影到多个参数上,并且可以被写为中缀和前缀形式。

.的右侧必须是一个list

q)L:(10 20 30; 40 50)
q)L[1][0]
40
q)L[1; 0]
40
q)L . 1 0
40
q)d:`a`b`c!(10 20 30; 40 50; enlist 60)
q)d[`b][0]
40
q)d[`b; 0]
40
q)d . (`b; 0)
40
q)g:{x+y}
q)g[1; 2]
3
q)g . 1 2
3

可以配合monadic函数使用.,其效果如下

q)f:{x*x}
q)f@5
25
q)f . enlist 5
25
q)f . enlist 1 2 3
1 4 9

为了表示一个隐藏的索引,可以使用::来代替

q)m:(1 2 3;4 5 6)
q)m[0;]
1 2 3
q)m . (0; ::)
1 2 3
q)m . (::; 1)
2 5

对于一个niladic函数的.执行形式,需要使用::生成一个list。

q)f:{6*7}
q)f . enlist (::)
42
q)f . enlist 42
42
All data structures in q are composed from lists and dictionaries.

一些很好的练习:

q)L:10 20 30
q)L . enlist 1
_
q)m:(10 20 30; 100 200 300)
q)m . 0 1
_
q)ds:(`a`b`c!10 20 30; `x`y!100 200)
q)ds . (0; `b)
_
q)mix:(10 20 30; `a`b`c!(1; 2; (300 400)))
q)mix . (1; `c; 1)
_
q)dc:`c1`c2!(1 2 3; `a`b`c)
q)dc . (`c2; 1)
_
q)t:([]c1:1 2 3;c2:`a`b`c)
q)t . (1; `c2)
_

答案分别是
20
20
20
400
`b
`b

3. 应用Monadic函数的@

回忆@的一般操作:

q)L:10 20 30 40 50
q)@[L;1]
20
q)@[L;0 1]
10 20

现在除了取值外,我们同时应用一个函数:

q)@[L;1;neg]
10 -20 30 40 50
q)@[L;0 2;neg]
-10 20 -30 40 50

注意到上述结果与正常在列表子集上的运算不同,正常只会返回在子集上运算的结果

q)neg L@0 1
-10 -20

而这个提升的版本会返回修改后的整个列表

Monadic函数使用@的一般应用 的语法是

@[L;I;f]

其中L是列表,I为索引的容器。这个形式可以泛化到任何可以被视为映射的数据结构,例如给定一个字典和一个键值列表

q)d:`a`b`c!10 20 30
q)ks:`a`c
q)@[d; ks; neg]
a| -10
b| 20
c| -30

上述操作都是在输入数据结构的拷贝上完成的。我们也可以通过pass-by-name的方法来进行in-place修改

q)L:10 20 30 40
q)@[L; 0; neg]
-10 20 30 40
q)L
10 20 30 40
q)@[`L; 0 ; neg]
`L
q)L
-10 20 30 40

4. 应用Dyadic函数的@
当Dyadic函数使用@时,需要提供一个额外的运算元,显然运算元要与子集的大小匹配。除了一种额外的情况,当运算元是atom时,会被自动拓展到与子集相同大小。

q)L:10 20 30 40
q)@[L; 0 1; +; 100 200]
110 220 30 40
q)@[L; 0 1; +; 100]
110 120 30 40
q)d:`a`b`c!10 20 30
q)@[d; `a`b; +; 100 200]
a| 110
b| 220
c| 30
q)@[d; `a`b; +; 100]
a| 110
b| 120
c| 30

Dyadic函数使用@的一般应用 的语法是

@[L;I;g;v]

其中LI与上小节定义一样,可以是任意能够被视为映射的数据结构;g是一个Dyadic函数;v是一个atom或者与I匹配的列表。

列表赋值: 一个非常有用的Dyadic函数应用是使用赋值符:在子集上赋值

q)L:10 20 30 40
q)@[L; 0 2; :; 42 43]
42 20 43 40

与Monadic函数一样,in-place操作可以通过pass-by-name形式

q)L:10 20 30 40
q)@[`L; 0 2; :; 42 43]
`L
q)L
42 20 43 40

5. 应用Monadic函数的.
总结一下,@是作用在数据结构的顶层,而.则是深度索引。

重新回顾一下.的前缀用法

q)m:(10 20 30; 100 200 300)
q).[m; 0 1]
20
q)d:`a`b`c!(10 20 30; 40 50; enlist 60)
q).[d; (`a; 1)]
20

应用monadic函数的.形式:

q).[m; 0 1; neg]
10 -20 30
100 200 300
q).[d; (`a; 1); neg]
a| 10 -20 30
b| 40 50
c| ,60

同样,若想in-place修改,则使用pass-by-name形式。

可以使用::来代替隐藏的索引

q).[m; (0; ::); neg]
-10 -20 -30
100 200 300
q)d:`a`b`c!(100 200 300; 400 500; enlist 600)
q).[d; (`a; ::); neg]
a| -100 -200 -300
b| 400 500
c| ,600
q).[d; (::; 0); neg]
a| -100 200 300
b| -400 500
c| ,-600

应用monadic函数的.一般形式为:

.[L; I; f]

7. 应用Dyadic函数的.

一般形式为

.[L;I;g;v]

其中g是Dyadic函数,v是atom或与I相对应的运算元

q)m:(10 20 30; 100 200 300)
q).[m; 0 1; +; 1]
10 21 30
100 200 300
q).[m; (::; 1); +; 1 2]
10 21 30
100 202 300
q)m
10 20 30
100 200 300
q).[`m; (::; 1); +; 1]
`m
q)m
10 21 30
100 200 300
q).[`m; (::; 1); :; 42]
`m
q)m
10 42 30
100 42 300
q)d:`a`b`c!(100 200 300; 400 500; enlist 600)
q).[d; (`a; 1); +; 1]
q).[d; (`a; ::); +; 1]
q).[d; (::; 0); +; 1]
q).[`d; (::; 0); :; 42]

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/17969.html

相关文章

  • 3. Q语言学习之路—Lists

    摘要:简单所有中的元素都是同种类型的,这种列表具有很好的储存和性能占据连续的储存空间。索引域如果索引在合理的边界之外,结果不是一个错误,而会返回一个值,表示,返回的值类型与第一个元素的类型一致。其结果是右侧元素占据左侧元素,除非右侧元素为值。 0. 概述 所有Q中的数据类型最终都是由list构造的:一个字段(dictionary)是由一对list构造的;一个表是一个特殊的字典;一个键表(ke...

    wwq0327 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<