4. Q語言學習之路— Operators
0. "Operators and Verbs Are Functions"
在q中,操作符(Operators)又稱為動詞(Verbs), 讀表示式3+2
按照從右到左的順序:3被加到
2,其中3是一個名詞(主語),操作符+
是一個動詞,2是一個名詞(賓語)。
1. 函式標識
下面介紹三種以後常見的函式分類:
monadic函式:f[x]
或者f x
dyadic函式:
g[x;y]
或者x g y
atomic函式:作用於資料結構的那個元素
例如+
是一個dyadic函式,它有如下兩種表達方法,都是等價的:
q) 2+3 q) +[2;3]
第二個式子很神奇,類似的表達方式還有:
q)=[2;3] 0b
更神奇的是,可以將二元運算子的字首和中綴組合在一起:
q)(2+)[3]
5
q)(2+)3
5
2. atomic函式的拓展
用法見如下幾個例子, 比較容易理解:
q)neg 1 2 3 -1 -2 -3 q)1 2 3+10 20 30 11 22 33 q)1 2 3+10 20 30 40 'length
q)100+1 2 3 101 102 103 q)1 2 3+100 101 102 103
1. 運算子優先順序
沒有運算子優先順序!
1. Left-of-Right解讀方法
由於q語言沒有運算子優先順序,但是有一個簡單的法則來解讀任何表示式:
Expressions are evaluatedleft-of-right
which equates to
Expressions are evaluatedright-to-left
類似於解讀複合函式f(g(x))
, 可以被解讀為f of g of x
, 同樣可以被解讀為x to g to f
。
注意:
當表示式的結果是中綴運算子的左操作元時,必須對該表示式加括號
,否則中綴運算子會作用在表示式最右邊的一個元素上。如下例所示:
q)2*3+4 14 q)(2*3)+4 10 q)4+2*3 10
2. 沒有運算子優先順序的原因
- 運算子優先順序的開銷較大,只有當解析完整個表示式後才能開始計算
- 操作符的優先順序往往會被括號所覆蓋
- 一些程式語言允許使用者自定義dyadic運算子,這就需要拓展運算子的優先級別來cover使用者定義的運算子,這就導致了複雜性。
2. Match~
作用於任意兩個q元素,當兩個元素相同(identical)時返回1b
, 不同時返回0b
。對於相互match的兩個元素,它們需要同樣的型別,同樣的大小,同樣的值, 但也可能佔據不同的儲存空間
,這也意味著,拷貝項在q中被認為是相同的。
q)42~40+2 1b q)42~42h 0b q)42f~42.0 1b q)42~`42 0b q)`42~"42" 0b q)4 2~2 4 0b q)42~(4 2;(1 0)) 0b q)(4 2)~(4;2*1) 1b q)(())~enlist () 0b q)(1; 2 3 4)~(1; (2; 3; 4)) 1b q)(1 2;3 4)~(1;2 3 4) 0b
3. 相等和關係運算符
1. 相等=
和不等<>
相等運算子=
和Match運算子~
不同之處在於,相等運算子=
是atom-wise
的,即atomic
函式。
相等運算子校驗的是兩個元素是否是值相等的,並不管元素的型別:
q)42=42i 1b q)42=42.0 1b q)42=0x42 0b q)42="*" 1b
最後一項說明了,char"*"
的underlying值和42
的underlying值是一樣的。
但對於日期型別,比較的是時間上的先後關係,而不是其underlying值
q)2000.01.01=2000.01.01D00:00:00.000000000 1b q)2015.01.01<2015.02m 1b q)12:00:00=12:00:00.000 1b
對於float元素的對比,q語言的容限是10^-14
。
2. 非零not
如果對應元素的underlying值是0,則返回1b;否則返回0b。
對於char型別,"\000"
為0;對於時間型別,千禧年0時刻的值為0。
3. 大小關係符>, <=, >, >=
對於char型別和numeric型別的比較,比較的是其underlying的數值。
symbol的比較按照字典序:
q)`a<`b 1b q)`abc<`aba 0b
4.基礎數學運算子+, -, *, %
與其它程式語言不同的是,在q語言中使用%
而不是/
代表除法,因為/
被用來作為註釋的分隔符,而且
q god
認為%
更接近與除號÷
。 :)
除號返回的結果總是float
型別。
5. 最大|
和最小&
|
返回左右運算元的最大元素,對於二元資料來說,可以簡化為邏輯運算子or
。&
返回左右運算元的最小元素,對於二元資料,簡化為and
。
q)42|43 43 q)0b|1b 1b q)1b&0b 0b q)42|0x2b 43 q)"a"|"z" "z" q)`a|`z / error 'type
|
和&
操作同樣是item-wise
的,如下例:
q)2|0 1 2 3 4 2 2 2 3 4 q)11010101b&01100101b 01000101b q)"zaphod"|"arthur" "zrthur"
對於二元資料的可讀性,|
可以被寫為or
,&
可以被寫為and
。
q)42 or 43 43
6. 修訂符(Amend):
一個對:
的過載是inplace 賦值
q)a:42
類似與C語言中的+=,-=
等,在q語言中,同樣有+:, -:, &=
,均表示inplace賦值
即使變數尚未被建立,也可以使用amend形式:
q)x 'x q)x+:42 q)x 42
一個非常有用的形式是,:
,對list進行inplace的append操作:
q)L:1 2 3 q)L,:4 q)L 1 2 3 4
Amend會自動做型別提升,除了,:
q)L:1.1 2 2 3.3 q)L[1]+:100 q)L,:100 'type
7. 指數基元:sqrt, exp, log, xexp, xlog
sqrt
和exp
與傳統程式語言相同,log
則是以自然對數e
為底的。
xexp
代表乘方,xlog
代表以左運算元為底的對數
q)2 xexp 5 32f q)-2 xexp .5 0n q)2 xlog 32 5f q)2 xlog -1 0n
8. 更多的數學運算基元
1. 商div
和 餘數mod
div
的結果是向下取整,mod
的計算公式是dividend – (dividend div divisor)
q)7 div 2 3 q)7 div 2.5 2 q)-7 div 2 -4 q)7 mod 2.5 2 q)-7 mod 2 1 q)7 mod 2 3 4 1 1 3
2. 取符號signum
其結果返回1i
代表正,-1i
代表負,0i
代表0.
3. 倒數reciprocal
q)reciprocal 0.02380952 42.00001 q)reciprocal 0.0 0w q)reciprocal -0.0 -0w
4.floor
與ceiling
floor
向下取整,ceiling
向上取整, 用floor
可以規整浮點數型別的位數
q)x:4.242 q)0.01floor 100x 4.24
For reasons known only to the q gods, floor and ceiling do not apply to short types.
q)floor 4h 'type
9. 時間型別的操作符
對同種時間型別的資料比較是針對其underlying的數值進行的;對於不同時間型別的資料,q會先將他們轉換到同種型別再對其underlying值作比較。
一些常見的操作:
q)2015.01.01+12:00:00.000000000 2015.01.01D12:00:00.000000000 q)2015.01.01D00:00:00.000000000-2014.01.01D00:00:00.000000000 365D00:00:00.000000000 q)12:00:00-11:00:00 1:00:00 q)12:00-11:00 1:00
10. 對inf
和null
的操作
float和int的inf
對應的二進位制表示如下:
ValueBit Representation 0Wh0111111111111111b -0Wh1000000000000001b 0Wi01111111111111111111111111111111b -0Wi10000000000000000000000000000001b 0W0111111111111111111111111111111111111111111111111111111111111111b -0W1000000000000000000000000000000000000000000000000000000000000001b
所有的null
值都相等(=
),因為它們都代表缺失值,但並不match
(~
),因為型別不同。
NaN
值都相等,並且not
對所有的null
值和inf
值都返回0b
,因為它們都不等於0.
q)not 0W 0b q)not -0w 0b q)not 0N 0b
對於任何數值型別:
null < negtative infinity < normal values < positive infinity
對於inf
值的大小,取決於他們型別的寬度,對於正無窮:
short < int < long < real < float
, 對於負無窮:
-float < -real < -long < -int < -short
q)0W<0w 1b q)-0w<0W 1b q)-10000000<0N 0b q)0N<42i 1b q)0n<-0w 1b
11. 別名(Alias)::
一個
alias
是一個表示式——它並不是表示式的結果,而是表示式本身。
1. 建立別名::
如下
b
是a
的
別名
,當a
改變時,
b
的值也跟著改變,但c
不會改變。
q)a:42 q)b::a q)c:a q)a:43 q)b 43 q)c 42
下面是一個更有趣的例子:
q)w::(x*x)+y*y q)x:3 q)y:4 q)w 25 q)y:5 q)w 34
注意:只有當alais
所依賴的變數發生變化時,才會被重新計算(re-evaluated)。
2. 別名 vs. 函式
我們可以定義函式如下
q)fu:{(x*x)+y*y} q)fu[3;4] 25
別名和函式的區別在於:
- 函式需要提供明確的引數;而對別名,你可以在程式的任意地方對變數賦值,而且當且僅當別名被引用時,表示式才會被計算。
- 函式並不儲存計算結果,而別名儲存計算結果。
3. 依賴關係
別名
依賴其表示式中的變數。其依賴關係儲存在系統字典中,可以通過命令
.z.b
或者命令\b
來獲取。
q)w::(x*x)+y*y q).z.b x| w y| w
4. 檢視view
別名常被用來建立一個數據庫的檢視:
q)t:([]c1:`a`b`c`a;c2:20 15 10 20;c3:99.5 99.45 99.42 99.4) q)v::select sym:c1,px:c3 from t where c1=`a q)v sym px -------- a 99.5 a 99.4 q)update c3:42.0 from `t where c1=`a `t q)v sym px ------ a42 a42
表的依賴項可以通過.z.b
檢視:
q).z.b t| v
End.