前言
在Q语言中,所有数据结构本质上可以看做来源于列表,如字典可以看做是一个列表对,表又是一个特殊的字典,键表又是一个特殊的表对。因此掌握列表非常重要。
列表分为普通列表和简单列表,简单列表只包含同类原子数据类型,它具有非常好的存储和数据处理上表现的更加优异。虽然Q的列表操作和其他函数语言中的列表操作比较类似,但是列表的存储和处理方式完全不同。
一、列表的介绍
列表是q语言的基本构建块,因此对列表的透彻理解非常重要。列表只是原子(原子元素)和其他列表(一个或多个原子的组)的有序集合。
1.1 列表的定义
列表用()括起来,里面的元素用“;”隔开,或者用空格隔开,如下是各种类型的列表:
q)(1;1.1;`1;"1") /general list(普通列表)
1
1.1
`1
"1"
q)(1;2;3) / simple list(简单列表)
1 2 3
q)("a";"b";"c";"d") / simple list(简单列表)
"abcd"
q)(`Life;`the;`Universe;`and;`Everything) / simple list(简单列表)
`Life`the`Universe`and`Everything
q)(-10.0;3.1415e;1b;`abc;"z") /general list(普通列表)
-10f
3.1415e
1b
`abc
"z"
q)((1;2;3);(4;5)) /nest list(嵌套列表)
1 2 3
4 5
q)((1;2;3);(`1;"2";3);4.4) /nest list(嵌套列表)
1 2 3
(`1;"2";3)
4.4
q)L1:1 2 3 /不用括号的形式创建列表
q)L2:4 5 6 /不用括号的形式创建列表
q)L1:(1;2;3) /将列表赋值给L1
q)L2:("a";"b";"c";"d") /将列表赋值给L2
q)L3:((1;2;3);(`1;"2";3);4.4) /将列表赋值给L3
q)L1
1 2 3
q)L2
"abcd"
q)L3
1 2 3
(`1;"2";3)
4.4
q)a:42
q)b:43
q)(a;b) /通过表达式创建列表
42 43
q)L1:1 2 3
q)L2: 4 5
q)(L1;L2) /通过表达式创建列表
1 2 3
4 5
q)L3:(count L1; sum L2) /通过表达式创建列表
q)L3
3 9
列表中的元素从左到右排序,是有序的数列。 例如列表1; 2和2; 1是不同的。 而SQL基于集合,这些集合本质上是无序的。这种区别导致q表上的查询语义与类似的SQL查询之间存在一些细微差别。 列表的内在顺序使得大型时间序列处理在会非常的快速,这相对于SQL来说是一个很大的优势。
1.2 Count
Count函数可以用于查看列表中含有多少个元素,具体如下:
q)count (1;1.1;`1;"1")
4
q)count ((1;2;3);(4;5)) /查询嵌套列表的元素数量
2
q)count ((1;2;3);(`1;"2";3);4.4) /查询两层嵌套列表的元素数量
3
q)count (`Life;`the;`Universe;`and;`Everything)
5
q)count `zaphod
1
由上可以看出嵌套列表返回的是第一层。
二、简单列表
简单列表只能包含同一类型的数据类型。简单列表将占用更好的内存,且处理速度上会更快。具体如下:
q)(100;200;300) /简单整数列表
100 200 300
q)(1h; 2h; 3h) /简单整数列表
1 2 3h
q)(100i; 200i; 300i) /简单整数列表
100 200 300i
q)(123.4567; 9876.543; 99.0) /简单浮点数列表
123.4567 9876.543 99
q)(0b;1b;0b;1b;1b) /简单布尔型列表
01011b
q)(0x20;0xa1;0xff) /简单十六进制列表
0x20a1ff
q)(`Life;`the;`Universe;`and;`Everything) /简单symbol型列表
`Life`the`Universe`and`Everything
q)("s"; "t"; "r"; "i"; "n"; "g") /简单字符串列表
"string"
q)(2000.01.01; 2001.01.01; 2002.01.01) /简单日期列表
2000.01.01 2001.01.01 2002.01.01
三、空列表
3.1 普通空列表
空列表顾名思义是没有任何元素的列表,定义空列表只需要用()就可以了,可以定义五制定类型的空列表,也可以定义制定类型的空列表,具体如下:
q)() /创建未指定类型空列表
q)L:() /创建未指定类型空列表
q)L
q)L:`long$() ./创建一个long类型的空列表L
q)L,:1 /为列表L增加一个“1”元素,没有任何提示则增加成功
q)L
,1 /只有一个元素的时候,返回时前面会有一个,号,表示是列表,而不是变量L的值为1
q)L,:2 /为列表L增加一个“2”元素,没有任何提示则增加成功
q)L
1 2
q)L,:3.3 /为列表L增加一个float的元素“3.3”
'type /添加失败,提示类型不同的错误
q)L
1 2
3.2 单元素列表
只含有一个元素的列表我们成为单元素列表。(42)这不是一个单元素列表,因为Q的编译器会自动的将(42)转换为42,所以是一个42的值,而不是列表。因此在Q中,创建单元素列表必须使用“enlist”操作符,具体如下:
q)(42) /这不是一个单元素列表,是一个42的值
42
q)enlist 42 /创建一个单元素列表
,42 /单元素列表返回时第一个元素前面会有一个逗号,当里面的元素增加到两个的时候前面的逗号就会消失。
q)("a")
"a"
q)enlist ("a") /创建一个单元的字符创列表
,"a"
q)type (42)
-7h
q)type enlist 42 /查看单元素列表的type类型
7h
四、索引
通过索引我们可以查找列表中的元素,和其他编程语言一样,索引也是从0开始,索引值必须是整数,可以通过一下几种方式来索引列表中的元素:
q)(100; 200; 300)[0] /第1种索引方式,通过在列表后面用[]来索引,[ ]中包含索引号
100
q)(100; 200; 300)[2]
300
q)L:(100 200 300)
q)L[1] /第2种索引方式,通过在列表变量后面用[]来索引,[ ]中包含索引号
200
q)L[3] /当索引号超出列表的长度时,则返回0N
0N
q)L[1]:66 /通过索引修改列表中的元素的值
q)L
100 66 300
q)L[2]:66.6 /通过索引修改列表中的元素的值,当新的类型与原类型不同时会提示类型错误
'type
q)L[3]:66 /通过索引修改列表中的元素的值,索引号超出列表长度时会提示length错误
'length
q)L:(-10.0; 3.1415e; 1b; `abc; "z")
q)L[1.0] /索引的值必须为整数,否则也会报类型错误
'type
q)L:(100 200 300)
q)L /第3种索引方式,这样的索引方式会返回列表中所有的值
100 200 300
q)L[::] /第4种索引方式,这样的索引方式会返回列表中所有的值
100 200 300
五、列表的合并
列表的合并可以通过“,”和“^”来进行合并。具体如下:
q)L1:1 2 3
q)L2: 4 5 6
q)L1,L2 /利用,号来合并两个列表,这样的方式是直接将两个列表拼接
1 2 3 4 5 6
q)L1:10 0N 30
q)L2:100 200 0N
q)L1^L2 /利用^号来合并两个列表,会发现这样的方式右边的不为空的值会替代左边的值,同时右边列表中的空值对应的左边的列表如果不是空值则会有左边列表中的值填补。
100 200 30
q)L2^L1
10 200 30
六、列表作为一个映射
我们可以将列表看成是一种映射,可以看成索引号与值的一个映射,例如:
L:(101;102;103;104)可以看成
L1:(`a; 123.45; 1b)可以看成:
七、嵌套列表
我们可以利用下图来形象的描述各个类型的列表:
复杂的数据类型都是利用嵌套列表来构建,我们可以利用列表来构建多层次的数据结构,其本质也是列表,但是嵌套列表的索引就比较复杂,深层的数据要查找出来需要分层索引,如:
q)L:(1;2;(100;200)) /具有两层结构的嵌套列表
q)L
1
2
100 200
q)L:(1;2;(100;200;(a;"b";`c))) /具有三层结构的嵌套列表
q)L
1
2
(100;200;(42;"b";`c))
q)L3:((1; 2h; 3j); ("a"; `bc`de); 1.23; 6)
q)count L3 /查看L3中第一层有多少个元素,这里会将(1; 2h; 3j)看成一个整体,算作一个元素
4
q)count L3[0] /查看L3中第一层中的索引号为0的元素中有多少个元素
3 /返回3刚好对应(1; 2h; 3j)这个列表中元素的个数
q)count L3[1] /查看L3中第一层中的索引号为1的元素中有多少个元素
2
q)count L3[2]
1
八、迭代索引和深度索引
在嵌套列表中,我们需要通过迭代索引和深度索引才能将嵌套列表中的深层元素查找出来,且都是从上往下的去索引查找。
迭代索引的操作如下:
q)L:(1; (100; 200; (1000; 2000; 3000; 4000)))
q)L[0] /查询第一层的0号元素值
1
q)L[1] /查询第一层的1号元素值
100
200
1000 2000 3000 4000
q)L[1][2] /查询第一层的1号元素中的2号元素值
1000 2000 3000 4000
q)L[1][2][0] /查询第一层的1号元素中的2号元素的0号元素值
1000
深度索引的操作如下:
q)L[1;2;0] /等价于迭代索引中的L[1][2][0]
1000
q)L:(1; (100; 200; (1000 2000 3000 4000)))
q)L[1; 2; 0]: 999 /通过深度所以来修改对应的值
q)L
1
(100;200;999 2000 3000 4000) /999已经修改成功
q)L[1][2][0]:42 /通过迭代索引的方式修改对应的元素无法修改
'assign
q)L[1][2][0]
999
九、用列表进行索引
我们也可以将索引号改为列表来索引列表中的值,这样就可以一起索引多个值出来,也可以通过变量来当做索引号进行索引,也可以用嵌套列表当做索引号来进行索引。具体如下:
q)L:100 200 300 400
q)L[0]
100
q)L[1]
200
q)L[0 1]
100 200
q)L[0;1]
'type
q)L[(0;1)]
100 200
q)L[(0;1;0;2)]
100 200 100 300
q)L[0 1 0 2]
100 200 100 300
q)Index:0 2
q)L[Index] /使用变量进行索引
100 300
q)L:100 200 300 400
q)L[(0 1; 2 3)] /使用嵌套列表进行索引,最后的结果也是嵌套列表
100 200
300 400
q)L:100 200 300 400
q)L[1 2 3]:20000 3000 4000 /我们也可以通过列表索引来修改多个列表值
q)L
100 20000 3000 4000
/这个相当于L[1]:20000,L[2]:3000,L[3]:4000
q)L:100 200 300 400
/下面的索引,我们也可以省略[ ]。
q)L 0 2
100 300
q)Index:0 2
q)L Index
100 300
十、省略索引
对于特殊的嵌套列表,例如矩阵,则在索引时会有一些难度,这时Elided Indices(暂且理解为省略索引吧)就非常有效了。具体如下:
q)m:(1 2 3 4; 100 200 300 400; 1000 2000 3000 4000)
q)m
1 2 3 4
100 200 300 400
1000 2000 3000 4000
q)m[1;] /返回第2行(由于从0开始,因此1代表第二行)的所有元素
100 200 300 400
q)m[;3] /返回所有行的第4个元素
4 400 4000
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[;1;0] /不给值就意味着这一层要全部查找
4
`z
"i"
q)L[;;2] /不给值就意味着这一层要全部查找
3 6
`c`x`2
"w e"
十一、 矩阵列表
矩阵列表为嵌套列表之一,具体如下:
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 /返回矩阵列表L的转置
1 10 100
2 20 200
3 30 300
q)M:flip L /将L的转置赋值给M
q)L[1;2]
30
q)M[2;1]
30
/通过L[1;2]和M[2;1]我们发现转置后索引号也要改变
十二、 非常实用的列表操作
1、 Find(?),查找元素值对应的索引号
2、 til,产生正整数
3、 distinct,去重
4、 where,返回1b的对应的索引号
5、 group,分组统计
具体如下:
q)1001 1002 1003?1002
1
q)1001 1002 1003?1002 1003
1 2
q)1001 1002 1003?1002 1003 1001
1 2 0
q)til 10 /注意起始值为0
0 1 2 3 4 5 6 7 8 9
q)1+til 10
1 2 3 4 5 6 7 8 9 10
q)2*til 10
0 2 4 6 8 10 12 14 16 18
q)distinct 1 2 3 2 3 4 6 4 3 5 6
1 2 3 4 6 5
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
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