3. Q语言学习之路—Lists

48次阅读

共计 5663 个字符,预计需要花费 15 分钟才能阅读完成。

0. 概述
所有 Q 中的数据类型最终都是由 list 构造的:一个字段 (dictionary) 是由一对 list 构造的;一个表是一个特殊的字典;一个键表(keyed table)是一对表。因此熟悉一下 list 还是很重要的。
List 支持索引取值,并且支持不同元素类型,可以把 q list 当作动态分配的数组。
1. 简介
1. 定义一个 list 是一个存储 q data 的有序容器,使用括号表示,并且使用分号来分割元素。
q)(1; 1.1; `1)
1
1.1
`1
q)(1;2;3)
1 2 3
q)(“a”;”b”;”c”;”d”)
“abcd”
q)(`Life;`the;`Universe;`and;`Everything)
`Life`the`Universe`and`Everything
q)(-10.0; 3.1415e; 1b; `abc; “z”)
-10f
3.1415e
1b
`abc
“z”
q)((1; 2; 3); (4; 5))
1 2 3
4 5
q)((1; 2; 3); (`1; “2”; 3); 4.4)
1 2 3
(`1;”2″;3)
4.4
注意到没个的输出结果不太一样,第一个和最后三个是 general list,意味着 list 中的元素非同质的。
list 同样可以被复制给变量:
q)L1:(1;2;3)
q)L2:(“z”;”a”;”p”;”h”;”o”;”d”)
q)L3:((1; 2; 3); (`1; “2”; 3); 4.4)
2. countcount 相当于 length, 返回 list 中元素的个数,类型为 long
q)count (1;2;3)
3
在 q3 中,list 中元素最多有 2^64- 1 个;在 q2 中,最多有 20 亿个。
count 也可以对 atom 进行操作,尽管它们不是 list,但仍返回 1:
q) count 42
1
类似于 count 的操作符还有 first 和 last,返回 list 中第一个和最后一个元素。
2. 简单 list
Simple list: 所有 list 中的元素都是同种类型的,这种列表具有很好的储存和性能(占据连续的储存空间)。
You can always use general list notation, even for simple lists. 当 q 检测到一个 list 中元素是同种类型的时候,它会自动地将 list 转换为简单 list。
1. 简单整型 list 对于任何数值类的 List,在表示的时候,都可以忽略掉括号和分号,元素之间用空格隔开。
q)(100;200;300)
100 200 300
q)100 200 300
100 200 300
q)100 200 300~(100; 200 ; 300)
1b

q)(1h; 2h; 3h)
1 2 3h
注意 1 2 3h 这种形式的表示,后缀 h 是作用在整个 List 的元素上,而 (1;2;3h) 中后缀 h 仅仅作用在最后一个元素上,该 list 是一个 general list.
q)(1; 2; 3h)
1
2
3h
2. 简单浮点型 list
q)123.4567 9876.543 99
123.4567 9876.543 99
q console 压缩了小数部分为 0 的浮点数,上式中的 99 不是整型:即当在一个 float list 中加入一个看似整型数字的时候,q 会认为仅仅省略了数字右边的小数部分,因此你仍然得到的是一个简单浮点型 list.
3. 简单 Binary list 甚至可以省略空格符,boolean 类型以后缀 b 结尾:
q)(0b;1b;0b;1b;1b)
01011b
q)01011b
01011b
byte 类型以 0x 开头:
q)(0x20;0xa1;0xff)
0x20a1ff
q)0x20a1ff~(0x20;0xa1;0xff)
1b
GUID 类型与 integer 类型一样,以空格符分离
q)3?0Ng
8c6b8b64-6815-6084-0a3e-178401251b68 5ae7962d-49f2-404d-5aec-f7c8abbae288 5a5..
4. 简单 Symbol list 中间没有空格分隔,如果有空格会报错
q)(`Life;`the;`Universe;`and;`Everything)
`Life`the`Universe`and`Everything
q)`Life`the`Universe`and`Everything
`Life`the`Universe`and`Everything

q)`bad `news
‘bad
5. 简单 char list 和 String
char list 的简化形式像许多语言中的 string 类型;事实上,char list 被称为 string,由于 string 是 list 类型,因此不能比较两个不同长度 string 的大小。
q)(“s”; “t”; “r”; “i”; “n”; “g”)
“string”
q)”string”
“string”
比较:
q)”string”=”text”
‘length
q)”string”~”text”
0b
6. 时间类型 list 由于它们实际上是整型,所以简化版本的 simple list 以空格符进行分隔:
q)(2000.01.01; 2001.01.01; 2002.01.01)
2000.01.01 2001.01.01 2002.01.01
q)(00:00:00.000; 00:00:01.000; 00:00:02.000)
00:00:00.000 00:00:01.000 00:00:02.000
对于混合日期类型的 list,所有元素的类型与第一个元素保持一致,可以追加一个类型指定符来指定 list 元素类型:
q)12:34 01:02:03
12:34:00 01:02:03

q)01:02:03 12:34 11:59:59.999u
01:02 12:34 11:59
3. 空和单例 list
1. 一般的空 list 以 () 或()表示一个空 list,其在 q console 中没有显示。可以使用 -3!()来强制显示()。
2. 单例 list 一个 singleton 表示一个只含有一个元素的 list. 由于 () 除了用来生成列表外,还是数学表达式中的符号,单单使用 (42) 会得到元数据 42,因此不可能用 () 来生成一个单例 list.
单例 list 用函数 enlist 来创建:
q)enlist 42
,42
只带有一个元素的 string 不能够被写为 ”a”,这只是一个 character 的元数据,应当使用 `enlist. This is a common error for qbies.
q)”a”
“a”
q)enlist “a”
, “a”
注意单例并不一定要以 atom 作为它仅有的元素,它可以是任何 q 元素:
q)enlist 1 2 3
1 2 3
q)enlist (10 20 30; `a`b`c)
10 20 30 a b c
4. 索引
1. 标识
以 [i] 的形式:
q)(100; 200; 300)[0]
100
q)100 200 300[0]
100
q)L:100 200 300
q)L[0]
100
2. 索引赋值
q)L:1 2 3
q)L[1]:42
q)L
1 42 3
注意向简单 list 赋值的时候,赋值类型必须与 list 元素的类型保持一致,否则会报错。
3. 索引域如果索引在合理的边界之外,结果不是一个错误,而会返回一个 Null 值,表示“missing data”,返回的 Null 值类型与第一个元素的类型一致。
q)L1:1 2 3 4
q)L1[4]
0N
q)L2:1.1 2.2 3.3
q)L2[-1]
0n
q)L3:(`1; 2; 3.3)
q)L3[0W]
`
4. 空索引和 Null 项
一个忽略的索引返回整个 list:
q)L:10 20 30 40
q)L[]
10 20 30 40
空索引与索引为空的 list 不同,后者会返回一个空的 list,可以用指令 -3! 来强制显示
q)-3!L[()]
“()”
双冒号:: 代表 nil,即零 (无) 项,返 list 所有元素。
q)L[::]
10 20 30 40
同时,在 list 中使用:: 可以避免 general list 在被转换为 simple list 之后,无法再赋值的情况,具体见下例:
q)L:(::; 1 ; 2 ; 3; `a)
q)L[4]:4
q)L[4]:`a
5. 合并 list
1. , join
逗号连接符, 右边的 list 被拷贝到一个左边 list 的拷贝上,join 同时支持 atom,即支持作用于单元素。
q)1 2 3,4 5
1 2 3 4 5
q)1,2 3 4
1 2 3 4
q)1 2 3,4
1 2 3 4
可以使用 (), x 或者 x, () 来生成 x 的单元素 list,效果等同于 enlist x
2. ^ merge 另一种合并 list 的方法是,对于两个长度相等的 list, 可以使用 ^ 对它们合并。其结果是右侧元素占据左侧元素,除非右侧元素为 null 值。
q)L1:10 0N 30
q)L2:100 200 0N
q)L1^L2
100 200 30
6. list 作为 map
list 将索引 i 映射到元素 L[i]
I O
0 1 2
1 3 4
7. list 嵌套
1. 深度 list 中的元素为 list 称为嵌套,嵌套的层数为深度 depth,atom 的 depth 是 0,简单 list 的 depth 为 1.
q)L:(1;2;(100;200))
q)count L
3
2. 图例

8. list 多重索引
可以使用 L[1][2][0]或者 L[1;2;0](注意是分号)来读取元素,前者被称为 iterated indexing,后者被称为 index at depth。
其中,index at depth 方法可以赋值,但是 iterated indexing 不支持赋值操作:
q)L:(1; (100; 200; (1000 2000 3000 4000)))
q)L[1; 2; 0]: 999
q)L
(1; (100; 200; (999 2000 3000 4000)))
q)L[1][2][0]:42
‘assign
构造 matrix 的一个方法:Reshape 操作符 #,下面代码中的 0N(missing data)类似于 python 中的 -1
q)2 0N#til 10
0 1 2 3 4
5 6 7 8 9
q)0N 3#til 10
0 1 2
3 4 5
6 7 8
,9
9. 使用 list 索引
1. 提取多个元素我们可以使用简单 list 作为索引,索引可以是任意顺序,甚至可以是重复的。
q)L:100 200 300 400
q)L[0 2]
100 300
q)L[0 2 0]
100 300 100
2. 通过变量索引
q)L
100 200 300 400
q)I:0 2
q)L[I]
100 300
3. 通过嵌套 list 索引返回的结果与嵌套索引 list 具有相同的 shape
q)L:100 200 300 400
q)L[(0 1; 2 3)]
100 200
300 400
4. 通过索引 list 赋值
q)L[1 2 3]:2000 3000 4000
赋值操作是按照从左到右的顺序进行的
q)L[3 2 1]:999 888 777
is equivalent to,
q)L[3]:999
q)L[2]:888
q)L[1]:777
因此,如果对重复项进行赋值的时候,最右边的项被保留下来。
q)L:100 200 300 400
q)L[0 1 0 3]:1000 2000 3000 4000
q)L
3000 2000 300 4000
也可以对多个元素赋同一个值,使用下面的格式:
q)L:100 200 300 400
q)L[1 3]:999
q)L
100 999 300 999
5. 并列索引可以在 list 后仅仅使用空格符分隔来索引:
q)L:100 200 300 400
q)L[0]
100
q)L 0
100
q)L[2 1]
300 200
q)L 2 1
300 200
q)I:2 1
q)L I
300 200
q)L ::
100 200 300 400
6. ? 查找返回右侧元素在左侧 list 中的位置索引
q)1001 1002 1003?1002
1
如果所查找的元素不在 list 里,那么将会返回整个 list 的 count 值,即长度:
q)1001 1002 1003?1004
3
find 操作符右侧同样可以是一个 list
q)1001 1002 1003?1003 1001
10. 隐藏的索引
1. 矩阵的隐藏索引
q)m:(1 2 3 4; 100 200 300 400; 1000 2000 3000 4000)
q)m[1;]
100 200 300 400
m[;3]
4 400 4000
2. 深度嵌套 list 的隐藏索引
q)L:((1 2 3;4 5 6 7);(`a`b`c`d;`z`y`x`;`0`1`2);(“now”;”is”;”the”))
q)L
(1 2 3;4 5 6 7)
(`a`b`c`d;`z`y`x`;`0`1`2)
(“now”;”is”;”the”)
q)L[;1;]
4 5 6 7
`z`y`x`
“is”
q)L[;;2]
3 6
`c`x`2
“w e”
其中,L[;1;]表示取所有顶层元素在 index 1 的所有元素;L[;;2]表示取第二层元素在 index 2 的元素。
11. 方阵 list 和矩阵
1. 方阵
方阵 list 是一个包含长度相等 list 的 list,但这个方阵不一定是传统的矩阵,也可以是嵌套的矩阵,如下所示:
q)L:(1 2 3; (10 20; 100 200; 1000 2000))
q)L
1 2 3
10 20 100 200 1000 2000
可以使用 flip 函数对方阵进行转置操作,flip 操作会分配新的储存空间并且拷贝原数据。
q)L:(1 2 3; 10 20 30; 100 200 300)
q)L
1 2 3
10 20 30
100 200 300
q)flip L
1 10 100
2 20 200
3 30 300
2. 矩阵矩阵的正式定义是递归的,0 维矩阵是一个标量,1 维矩阵是一个简单 list;对于 n >1,n 维矩阵是一个 size 相等的 n - 1 维矩阵的 list。
可以通过 list 来索引一个矩阵:
q)m:(1 2; 10 20; 100 200; 1000 2000)
q)m 0 2
1 2
100 200
12. 一些有用的 list 操作符
1. til 以一个非负整数作为参数,返回从 0 开始的连续自然数
q)til 10
0 1 2 3 4 5 6 7 8 9
q)1+til 10
q)2*til 10
q)1+2*til 10
q)-5+4*til 3
2. distinct
q)distinct 1 2 3 2 3 4 6 4 3 5 6
1 2 3 4 6 5
3. where 返回 1b 对应位置上的元素
q)where 101010b
0 2 4
q)L:10 20 30 40 50
q)L[where L>20]:42
q)L
10 20 42 42 42
4. group 返回所有元素出现的位置
q)group “i miss mississippi”
i| 0 3 8 11 14 17
| 1 6
m| 2 7
s| 4 5 9 10 12 13
p| 15 16

End.

正文完
 0