摘要:接下來幾章將進(jìn)入語言的核心內(nèi)容函數(shù)表數(shù)據(jù)轉(zhuǎn)換查詢和等等,函數(shù)說明在中,函數(shù)是可以修改全局變量的,所以并不是一個(gè)純正的函數(shù)式語言。函數(shù)體內(nèi)最大的局部變量個(gè)數(shù)為個(gè)。當(dāng)執(zhí)行操作時(shí),當(dāng)前項(xiàng)是函數(shù)的左運(yùn)算元,前一項(xiàng)是函數(shù)的右運(yùn)算元。
接下來幾章將進(jìn)入Q語言的核心內(nèi)容——函數(shù)、表、數(shù)據(jù)轉(zhuǎn)換、查詢和I/O等等, excited :)
1. 函數(shù)說明在q中,函數(shù)是可以修改全局變量的,所以q并不是一個(gè)純正的函數(shù)式語言。
1. 函數(shù)定義
使用花括號(hào){和},函數(shù)的輸入輸出類型不用指定,甚至函數(shù)名都可以不用指定。如下是一個(gè)完整的函數(shù)定義:
q) {[x] x*x}
調(diào)用函數(shù)時(shí),參數(shù)用中括號(hào)包圍起來,參數(shù)通過分號(hào);分隔
q){[x] x*x}[3] 9
函數(shù)可以賦值給一個(gè)變量:
q)f:{[x] x*x} q)f[3] 9
2. 函數(shù)標(biāo)識(shí)和術(shù)語
函數(shù)的正式定義為{[p1;...;pn] e1; ...; em},其中可選的p1;...;pn是正式的參數(shù),e1; ...; em是執(zhí)行的表達(dá)式,雖然是從左向右寫的,但是仍然是從右向左執(zhí)行的。
函數(shù)的參數(shù)個(gè)數(shù)被稱為函數(shù)的valence, 最常見的函數(shù)是monadic(valence 1)和dyadic(valence 2)。
一個(gè)niladic函數(shù)是指一個(gè)沒有輸入的函數(shù),表示如下:
f:{[] … }
例子如下:
q){[] 42} / pure function returns constant 42 42 q){[] a*a} / impure function: references global a {[] a*a}
函數(shù)最大的參數(shù)個(gè)數(shù)(valence)為8,超過8個(gè)參數(shù)將會(huì)報(bào)錯(cuò)。如果參數(shù)較多的話,將參數(shù)打包成list或者dictionary輸入函數(shù)。
函數(shù)的輸出值為函數(shù)最后一個(gè)表達(dá)式的結(jié)果:
q){[x] x*x} q){[x;y] a:x*x; b:y*y; r:a+b; r}
Keep it short. 很多q語言中的函數(shù)都是緊湊并且模塊化的,很多函數(shù)都是僅僅一行
3. 函數(shù)應(yīng)用
函數(shù)的調(diào)用是嚴(yán)格的,意味著在參數(shù)替換之前,表達(dá)式就已經(jīng)被執(zhí)行了:
q)f:{[x] x*x} q)f[0N!3+1] 4 16
當(dāng)提供的參數(shù)多于函數(shù)定義的參數(shù)時(shí),會(huì)報(bào)"rank錯(cuò)誤。
q) {[x] x*x}[3;4] "rank
4. 沒有返回值的函數(shù)
函數(shù)體最后只有一個(gè)分號(hào);,返回::。
q)fvoid:{[x] `a set x;} q)fvoid 42 q)a 42
注意在q中,分號(hào);是分隔符而并不是終止符。
5. 參數(shù)的并列寫法
類似于列表索引和字典取值,函數(shù)的參數(shù)也可以是并列寫法:
q){[x] 2*x} 42 84 q)f:{[x] x*x} q)f 5 25
6. 函數(shù)名的應(yīng)用
當(dāng)函數(shù)被賦值給一個(gè)全局變量時(shí),可以通過symbol形式的函數(shù)名來調(diào)用:
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. 隱含的參數(shù)
當(dāng)一個(gè)函數(shù)沒有參數(shù)被明確定義時(shí),三個(gè)隱含的參數(shù)x, y, z會(huì)被自動(dòng)定義,下面的函數(shù)定義是等價(jià)的:
{[x] x*x} {x*x}
{[x;y] x+y} {x+y}
三個(gè)參數(shù)x, y, z的調(diào)用是按照先后順序的,意味著x總是第一個(gè)被調(diào)用,y第二個(gè),z第三個(gè)。下面這個(gè)函數(shù)只有提供三個(gè)參數(shù)值時(shí)才會(huì)返回值
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. 匿名函數(shù)和lambda表達(dá)式
一個(gè)沒有函數(shù)名稱的函數(shù)叫做匿名函數(shù),匿名函數(shù)的常見的兩個(gè)用處:
定義在函數(shù)內(nèi)的匿名函數(shù)
f{[...] ...; {...}[...]; ...}
函數(shù)容器
q)powers:({1}; {x}; {x*x}; {x*x*x}) … q)selected:2 q)powers[selected] {x*x}
9. 恒等函數(shù)::
恒等函數(shù)::返回它的輸入作為輸出;裸的恒等函數(shù)不能使用并列的形式,它必須使用中括號(hào)調(diào)用。
q)::[42] 42 q)::[`a`b`c] `a`b`c q):: 42 / error " q)(::) 42 42
10. 函數(shù)是數(shù)據(jù)
類似于python中的函數(shù)是對(duì)象一樣,在q語言中函數(shù)都是數(shù)據(jù),可以作為輸入和輸出。
q)apply:{x y} q)sq:{x*x} q)apply[sq; 5] 252. 通過名字調(diào)用
常規(guī)的函數(shù)使用傳值調(diào)用(call-by-value),意味著參數(shù)在被傳遞時(shí)是按值傳遞的,在這個(gè)過程中,原始值被拷貝了一份,以保證之前的原始數(shù)據(jù)不會(huì)被修改。但這樣做的一個(gè)問題是,當(dāng)輸入?yún)?shù)的size非常大時(shí),拷貝是被禁止的。這個(gè)時(shí)候就有一個(gè)新的方法:call-by-name,在這種情況下變量的名字被傳遞而不是變量的值。
Call-by-name沒有特別的語法。一個(gè)例子就是內(nèi)置函數(shù)get,傳遞全局變量的名字,返回對(duì)應(yīng)的值
q)a:42 q)get `a 42
另一個(gè)例子是函數(shù)set,是給全局變量賦值
q)`a set 43 `a q)a 433. 局部和全局變量
1. 定義局部和全局變量
在函數(shù)體內(nèi)使用:定義的變量被稱為局部變量。函數(shù)體內(nèi)最大的局部變量個(gè)數(shù)為24個(gè)。
q)f:{a:42; a+x}
q語言不遵循詞法作用域規(guī)則,意味著在函數(shù)體內(nèi)的函數(shù)并沒有獲得上層函數(shù)體內(nèi)變量的權(quán)限,例如下例中, helper函數(shù)并沒有獲取局部變量a的值的權(quán)限
q)f:{[p1] a:42; helper:{[p2] a*p2}; helper p1}
然而,你必須對(duì)該局部函數(shù)聲明一個(gè)額外的參數(shù)來傳遞局部變量
q)f:{[p1] a:42; helper:{[a; p2] a*p2}[a;]; helper p1} q)f 5 210
在所有函數(shù)定義以外的變量被稱為全局變量。
2. 在函數(shù)內(nèi)對(duì)全局變量賦值
當(dāng)函數(shù)體內(nèi)沒有同名的局部變量時(shí),可以使用雙冒號(hào)::來對(duì)全局變量進(jìn)行賦值;
`q)b:6
q)f:{b::7; x*b}
q)f[6]
42
q)b
7`
而當(dāng)函數(shù)體內(nèi)有同名的局部變量時(shí),雙冒號(hào)符操作的是局部變量,并不是全局變量
q)b:6 q)f:{b:42; b::x; b} q)f[98] 98 q)b 6
相比::,更推薦使用set來進(jìn)行全局變量修改, 這樣就不會(huì)有局部變量名沖突了。
q)a:42 q)f:{a:98.6; `a set x} q)f 43 `a q)a 434. 投影
投影是指只指定函數(shù)的一部分參數(shù),其結(jié)果會(huì)是其余參數(shù)的函數(shù)。
1. 函數(shù)投影
一個(gè)函數(shù)投影的例子為:
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作用于參數(shù)2,返回一個(gè)函數(shù);該函數(shù)作用于參數(shù)3,返回一個(gè)函數(shù);最后作用于4,返回結(jié)果9。上式等價(jià)于add3[2;3;4]。
No second look. 被賦值的函數(shù)投影變量不會(huì)隨著原函數(shù)的改變而改變
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. 運(yùn)算符投影
當(dāng)使用運(yùn)算符中綴形式的時(shí)候,一個(gè)q的運(yùn)算符可以通過固定其左運(yùn)算元來進(jìn)行投影,這時(shí)需要括號(hào)。
q)(7*) 6 42
由于任何操作符都是一個(gè)函數(shù),當(dāng)然可以使用其前綴形式進(jìn)行投影:
q)-[;42] 98 56
上面兩個(gè)公式中的空格符都不是必須的:
q)(7*)6 42 q)-[;42]98 56
3. 多維投影
當(dāng)函數(shù)有多個(gè)參數(shù)的時(shí)候(valence > 2),函數(shù)可以有多個(gè)投影,例如下例
q){x+y+z}[1;;3] {x+y+z}[1;;3] q){x+y+z}[1;;3] 2 65. Atomic函數(shù)
一個(gè)Atomic函數(shù)是指該函數(shù)直接作用于一個(gè)q數(shù)據(jù)結(jié)構(gòu)中的atom數(shù)據(jù)。
1. Monadic Atomic函數(shù)和map
回憶一下,monadic函數(shù)是指只作用于一個(gè)參數(shù)的函數(shù),如下是一個(gè)monadic atomic函數(shù)的例子,該函數(shù)作用于一個(gè)字典
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函數(shù)和zip
Dyadic函數(shù)是指作用于兩個(gè)參數(shù)的函數(shù)。若將dyadic函數(shù)的非atomic部分固定下來(可以看成一個(gè)函數(shù)的投影),那么dyadic函數(shù)就變?yōu)閙onadic函數(shù)。如下例中的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
在算術(shù)中,比較和關(guān)系運(yùn)算符都是atomic的,在這種應(yīng)用下會(huì)有四種情況:
atom和atom
atom和list
list和atom
list和list
在最后一種情況下,兩個(gè)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
這個(gè)功能相當(dāng)于傳統(tǒng)語言中的zip
3. 構(gòu)造atomic函數(shù)
簡單想一想就可以明白,由atomic函數(shù)構(gòu)成的函數(shù)仍然是atomic的,因此構(gòu)造一個(gè)atomic函數(shù)的方法就是去包含內(nèi)置的atomic函數(shù)。
構(gòu)造Monadic atomic函數(shù):
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
構(gòu)造Dyadic atomic函數(shù):
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.2426416. 副詞
副詞是高階的函數(shù),用以改變函數(shù)在列表上的應(yīng)用方式。這個(gè)術(shù)語來自于將q操作符當(dāng)做動(dòng)詞。
Proficiency in the use of adverbs is one skill that separates q pretenders from q contenders. :)
1. Monadic each
合并函數(shù)例如count只會(huì)作用在嵌套列表的最高層級(jí):
q)count 10 20 30 3 q)count (10 20 30; 40 50) 2
如果我們想知道嵌套列表中每個(gè)元素的長度,這個(gè)時(shí)候副詞each就派上用場(chǎng)了,它使得monadic函數(shù)能夠作用于列表的每個(gè)元素而不是整個(gè)列表,each有兩種使用方法:
中綴形式:each緊跟在函數(shù)的后面
q) count each (10 20 30; 40 50) 3 2
前綴形式
q) each[count] (10 20 30; 40 50) 3 2
對(duì)于層數(shù)較深的嵌套矩陣,可能需要對(duì)each進(jìn)行迭代
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")
當(dāng)想要將一個(gè)長度為n的向量轉(zhuǎn)換為一個(gè)大小為n*1的矩陣時(shí),可以使用enlist each來實(shí)現(xiàn),但flip enlist在大列表上執(zhí)行更快。
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符號(hào)"作用在一個(gè)dyadic函數(shù)上,使得函數(shù)能夠成對(duì)地作用在對(duì)應(yīng)的列表元素上,符號(hào)"讀作"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"
當(dāng)熟練的時(shí)候,可以使用each-both的前綴形式:
q),"[("abc"; "uv"); ("de"; "xyz")] "abcde" "uvxyz"
一個(gè)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操作符作用于一個(gè)dyadic函數(shù),使第一個(gè)參數(shù)下的每一項(xiàng)都應(yīng)用于第二個(gè)參數(shù):
("abc"; "de"; enlist "f") ,: ">" "abc>" "de>" "f>"
4. each-right /:
each-right 作用于一個(gè)dyadic函數(shù),使第一項(xiàng)作用于第二個(gè)參數(shù)的每一項(xiàng):
q)"",/:("abc";"de";enlist "f") "5. Cross Product
叉積(Cross Product)成對(duì)地作用于左側(cè)的每一項(xiàng)和右側(cè)的每一項(xiàng)。 如果我們對(duì)join執(zhí)行each-right和each-left操作,再內(nèi)置函數(shù)raze對(duì)得到的嵌套矩陣夷平,就可以得到我們想要的結(jié)果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上述操作還是較為復(fù)雜,我們可以通過內(nèi)置函數(shù)cross來得到上述結(jié)果
q)1 2 3 cross 10 20 1 10 1 20 2 10 2 20 3 10 3 20可以注意到,若我們組合each-left和each-right時(shí),我們便可以得到上述結(jié)果的轉(zhuǎn)置
q)raze 1 2 3,:/:10 20 1 10 2 10 3 10 1 20 2 20 3 206. Over /
Over操作符/是一個(gè)提供遞歸機(jī)制的高階函數(shù)。它最簡單的形式是修改一個(gè)dyadic函數(shù),使其在一個(gè)list上累積函數(shù)作用的結(jié)果q)0 +/ 1 2 3 4 5 6 7 8 9 10 55注意: 在運(yùn)算符和/之間不能存在空格,因?yàn)?b>/可以被用作注釋。
運(yùn)算符左運(yùn)算元為累積計(jì)算的初始值,右運(yùn)算元為待累積計(jì)算的列表。
但我們也可以省略左運(yùn)算元(即初始值),這個(gè)時(shí)候需要我們對(duì)表達(dá)式做一些變換,被作用函數(shù)和Over運(yùn)算符/用括號(hào)包住,這時(shí)右邊列表的第一個(gè)元素就是初始值。
q)(+/) 1 2 3 4 5 6 7 8 9 10 55上面的括號(hào)是必需項(xiàng),被修改的函數(shù)實(shí)際上是一個(gè)monadic函數(shù)。
一些有用的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使用,/可以高效地移除列表的頂層嵌套,其對(duì)應(yīng)的內(nèi)置函數(shù)為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 5007. Iteration
/的另一種用法是作為循環(huán)代碼的等價(jià)形式。在這個(gè)版本下,左運(yùn)算元表示了循環(huán)的次數(shù),右運(yùn)算元為初始值。例如,計(jì)算Fibonacci數(shù)列: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另一個(gè)版本的/控制了循環(huán)的進(jìn)行直至收斂,或者檢測(cè)到一個(gè)環(huán)的存在。下面以牛頓法為例介紹這種循環(huán)的使用,我們使用牛頓法來尋找函數(shù){-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.414214q語言會(huì)判斷當(dāng)前的輸出值與之前的輸出值之間的大小,如果兩個(gè)值之間相差在一定的tolerance以內(nèi),則認(rèn)為算法收斂并且迭代完成;否則繼續(xù)執(zhí)行循環(huán)任務(wù)。
此外,q語言通過每次比較運(yùn)算結(jié)果和初始值是否match(~)來判斷當(dāng)前程序是否存在環(huán)(loop),如果存在環(huán),程序則終止:
q)newtcycle:{[xn] xn-((xn*xn*xn)+(-2*xn)+2)%-2+3*xn*xn} q)newtcycle/[0.0] 1f如果運(yùn)算的結(jié)果與初始值相等,但是類型不同(not match),程序則不會(huì)停止;例如上例中如果提供初始值0,則程序會(huì)一直運(yùn)行下去。
運(yùn)算符/的最后一種重載用法,等價(jià)于使用while循環(huán),它提供了一個(gè)判斷條件,若每次的運(yùn)算結(jié)果滿足條件,則繼續(xù)執(zhí)行;否則,終止計(jì)算
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 15978. Scan
Scan操作符同樣是一個(gè)高階函數(shù),其作用與操作符/一樣,與其不同的是,Scan會(huì)返回中間的計(jì)算結(jié)果??梢园裇can當(dāng)做是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操作符的好處是可以看到函數(shù)中間過程的運(yùn)行結(jié)果。
q)fib:{x, sum -2#x} q)fib[{1000>last x}; 1 1]9. each-previous ":
each-previous操作符對(duì)列表的每項(xiàng)和其前一項(xiàng)執(zhí)行dyadic函數(shù)操作。當(dāng)執(zhí)行Dyadic操作時(shí),當(dāng)前項(xiàng)是Dyadic函數(shù)的左運(yùn)算元,前一項(xiàng)是Dyadic函數(shù)的右運(yùn)算元。由于列表中第一項(xiàng)沒有前項(xiàng),所以我們必須在運(yùn)算符:"左運(yùn)算元的位置提供初始值,如下例
q)100 -": 100 99 101 102 101 0 -1 2 1 -1與其它副詞一樣,each-previous :"也有一個(gè)monadic函數(shù)的形式。但在這種形式下,列表中的第一個(gè)元素不會(huì)被當(dāng)做初始的前項(xiàng),相反,它直接返回該項(xiàng)。
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保留第一項(xiàng)的動(dòng)機(jī)是,可以通過保留的第一項(xiàng)來恢復(fù)整個(gè)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當(dāng)我們需要返回的結(jié)果中都是變化值時(shí),可以通過如下方法得到
q)deltas0:{first[x] -": x} q)deltas0 100 99 101 102 101 0 -1 2 1 -1一個(gè)使用each-previous的非常有用的工具是使用~判斷連續(xù)項(xiàng)是否是match的。實(shí)際中,我們經(jīng)常會(huì)關(guān)注兩個(gè)連續(xù)項(xiàng)不同的情況,這種情況下使用內(nèi)置函數(shù)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可以對(duì)differ的結(jié)果使用where和cut來分隔列表
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的練習(xí)
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用一行代碼來實(shí)現(xiàn)上面的代碼
q) runs where ct=max ct:count each runs:(where differ L) cut L同樣,我們可以上述技術(shù)來找到上升和下降子序列
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 138. 一般應(yīng)用Thorough understanding of the general application is another test that separates the q pretenders from the contenders.1. 動(dòng)詞 @
q語言的基礎(chǔ)操作包括:從list中通過索引取值,在字典中通過鍵取值或執(zhí)行一個(gè)monadic函數(shù)。
高階函數(shù)@是q語言中基礎(chǔ)操作的真正形式,它將一個(gè)monadic映射(可能是索引取值,字典取值或者monadic函數(shù))作用于一個(gè)元素之上。與所有的內(nèi)置函數(shù)一樣,它同樣有中綴和前綴的表示形式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當(dāng)@與niladic函數(shù)應(yīng)用時(shí),可以使用空元素::來代表空值
q)f:{6*7} q)f[] 42 q)@[f; ::] 42 q)f@(::) 42 q)f@43 422. 動(dòng)詞.
q語言中,多元映射包括了:深度索引一個(gè)列表,從一個(gè)字典中取一個(gè)被嵌套的值和執(zhí)行一個(gè)帶有多個(gè)參數(shù)的函數(shù)等。高階函數(shù).是q語言中多元應(yīng)用的真正形式。它將多元映射投影到多個(gè)參數(shù)上,并且可以被寫為中綴和前綴形式。.的右側(cè)必須是一個(gè)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函數(shù)使用.,其效果如下
q)f:{x*x} q)f@5 25 q)f . enlist 5 25 q)f . enlist 1 2 3 1 4 9為了表示一個(gè)隱藏的索引,可以使用::來代替
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對(duì)于一個(gè)niladic函數(shù)的.執(zhí)行形式,需要使用::生成一個(gè)list。
q)f:{6*7} q)f . enlist (::) 42 q)f . enlist 42 42All data structures in q are composed from lists and dictionaries.一些很好的練習(xí):
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
`b3. 應(yīng)用Monadic函數(shù)的@
回憶@的一般操作:
q)L:10 20 30 40 50 q)@[L;1] 20 q)@[L;0 1] 10 20現(xiàn)在除了取值外,我們同時(shí)應(yīng)用一個(gè)函數(shù):
q)@[L;1;neg] 10 -20 30 40 50 q)@[L;0 2;neg] -10 20 -30 40 50注意到上述結(jié)果與正常在列表子集上的運(yùn)算不同,正常只會(huì)返回在子集上運(yùn)算的結(jié)果
q)neg L@0 1 -10 -20而這個(gè)提升的版本會(huì)返回修改后的整個(gè)列表。
Monadic函數(shù)使用@的一般應(yīng)用 的語法是
@[L;I;f]其中L是列表,I為索引的容器。這個(gè)形式可以泛化到任何可以被視為映射的數(shù)據(jù)結(jié)構(gòu),例如給定一個(gè)字典和一個(gè)鍵值列表
q)d:`a`b`c!10 20 30 q)ks:`a`c q)@[d; ks; neg] a| -10 b| 20 c| -30上述操作都是在輸入數(shù)據(jù)結(jié)構(gòu)的拷貝上完成的。我們也可以通過pass-by-name的方法來進(jìn)行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 404. 應(yīng)用Dyadic函數(shù)的@
當(dāng)Dyadic函數(shù)使用@時(shí),需要提供一個(gè)額外的運(yùn)算元,顯然運(yùn)算元要與子集的大小匹配。除了一種額外的情況,當(dāng)運(yùn)算元是atom時(shí),會(huì)被自動(dòng)拓展到與子集相同大小。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| 30Dyadic函數(shù)使用@的一般應(yīng)用 的語法是
@[L;I;g;v]其中L和I與上小節(jié)定義一樣,可以是任意能夠被視為映射的數(shù)據(jù)結(jié)構(gòu);g是一個(gè)Dyadic函數(shù);v是一個(gè)atom或者與I匹配的列表。
列表賦值: 一個(gè)非常有用的Dyadic函數(shù)應(yīng)用是使用賦值符:在子集上賦值
q)L:10 20 30 40 q)@[L; 0 2; :; 42 43] 42 20 43 40與Monadic函數(shù)一樣,in-place操作可以通過pass-by-name形式
q)L:10 20 30 40 q)@[`L; 0 2; :; 42 43] `L q)L 42 20 43 405. 應(yīng)用Monadic函數(shù)的.
總結(jié)一下,@是作用在數(shù)據(jù)結(jié)構(gòu)的頂層,而.則是深度索引。重新回顧一下.的前綴用法
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應(yīng)用monadic函數(shù)的.形式:
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應(yīng)用monadic函數(shù)的.一般形式為:
.[L; I; f]7. 應(yīng)用Dyadic函數(shù)的.
一般形式為
.[L;I;g;v]其中g是Dyadic函數(shù),v是atom或與I相對(duì)應(yīng)的運(yùn)算元
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]
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/17969.html
摘要:簡單所有中的元素都是同種類型的,這種列表具有很好的儲(chǔ)存和性能占據(jù)連續(xù)的儲(chǔ)存空間。索引域如果索引在合理的邊界之外,結(jié)果不是一個(gè)錯(cuò)誤,而會(huì)返回一個(gè)值,表示,返回的值類型與第一個(gè)元素的類型一致。其結(jié)果是右側(cè)元素占據(jù)左側(cè)元素,除非右側(cè)元素為值。 0. 概述 所有Q中的數(shù)據(jù)類型最終都是由list構(gòu)造的:一個(gè)字段(dictionary)是由一對(duì)list構(gòu)造的;一個(gè)表是一個(gè)特殊的字典;一個(gè)鍵表(ke...
閱讀 2415·2021-09-08 09:45
閱讀 3363·2021-09-08 09:45
閱讀 3106·2019-08-30 15:54
閱讀 3361·2019-08-26 13:54
閱讀 1417·2019-08-26 13:26
閱讀 1394·2019-08-26 13:23
閱讀 917·2019-08-23 17:57
閱讀 2187·2019-08-23 17:14