KDB/Q函数式查询:value/eval与colist符号化使用差异及疑问
测试环境与代码
q)t:([] e:1 2 3 4 5 6; a:0 0 1 2 3 4; b: 1 2 0 0 3 4; c:1 2 3 4 0 1) q)t e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0 6 4 4 1 q)colist: `a`b`c q)colist `a`b`c
使用value的函数式查询
q)?[`t; enlist(any;(enlist,value (each;{(=;x;0)};colist))); 0b; ()] e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0
符号化colist时value查询失败
q)?[`t; enlist(any;(enlist,value (each;{(=;x;0)};`colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,value (each;{(=;x;0)};`colist))); 0b; ()] ^
符号化colist时eval查询生效
q)?[`t; enlist(any;(enlist,eval (each;{(=;x;0)};`colist))); 0b; ()] e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0
非符号化colist时eval查询失败
q)?[`t; enlist(any;(enlist,eval (each;{(=;x;0)};colist))); 0b; ()] 'c [0] ?[`t; enlist(any;(enlist,eval (each;{(=;x;0)};colist))); 0b; ()] ^
K版本each(k){x'y})配合value生效
q)?[`t; enlist(any;(enlist,value ("k){x'y}";{(=;x;0)};colist))); 0b; ()] e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0
K版本each配合eval失败
q)?[`t; enlist(any;(enlist,eval ("k){x'y}";{(=;x;0)};`colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,eval ("k){x'y}";{(=;x;0)};`colist))); 0b; ()] ^
不使用value或eval时函数式查询普遍失败
q)?[`t; enlist(any;(enlist,(each; {(=;x;0)};`colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,(each; {(=;x;0)};`colist))); 0b; ()] ^ q)?[`t; enlist(any;(enlist,(each; {(=;x;0)};colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,(each; {(=;x;0)};colist))); 0b; ()] ^ q)?[`t; enlist(any;(enlist,("k){x'y}"; {(=;x;0)};`colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,("k){x'y}"; {(=;x;0)};`colist))); 0b; ()] ^ q)?[`t; enlist(any;(enlist,("k){x'y}"; {(=;x;0)};colist))); 0b; ()] 'type [0] ?[`t; enlist(any;(enlist,("k){x'y}"; {(=;x;0)};colist))); 0b; ()] ^
技术疑问
- 为何使用
value的函数式查询需非符号化colist,而eval版本需符号化colist? - 如何在
eval版本的函数式查询中集成K版本的each(k){x'y})? - 是否存在无需
value或eval即可生效的函数式查询实现方式?
问题解答
1. value与eval对colist形式要求不同的原因
value和eval的核心逻辑完全不同:
value是直接求值传入的表达式结构。当传入非符号化的colist(即值abc)时,(each;{(=;x;0)};colist)会被解析为将函数逐个应用到列名列表的每个元素上,生成(=;a;0),(=;b;0),(=;c;0)的合法条件;但如果传入符号colist,结构会变成把函数应用到符号colist本身,生成(=;colist;0),这是符号与整数的类型比较,直接触发'type错误。eval是将传入的AST结构当作Q代码执行。当传入符号colist时,AST会被解析为{(=;x;0)} each colist,eval会自动把符号colist解析为变量名并取其值abc,生成合法条件;但如果传入非符号化的colist(值abc),AST会被解析为{(=;x;0)} eachabc,Q会尝试把abc当作全局变量查找,找不到就触发'c`这类未定义变量错误。
2. 在eval版本集成K版本each的方法
K版本的each是函数形式的lambda({x'y}),可以先将其赋值为一个变量,再在eval的AST中使用这个变量替代原有的each:
q)keach: value "k){x'y}" // 定义K版本each为变量 q)?[`t; enlist(any;(enlist,eval (keach; {(=;x;0)}; `colist))); 0b; ()] e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0
原理是eval会把(keach; f; colist)解析为keach[f; colist],而keach作为K版本each函数,能正确实现f each colist`的逻辑,生成合法条件列表。
3. 无需value或eval的实现方式
存在,直接使用Q原生的函数式运算符/:(each-right)替代each,它是f each list的函数式等价写法,函数式查询的?运算符可以直接解析这个结构,不需要额外求值:
q)?[`t; enlist(any; enlist, (/:; {(=;x;0)}; colist)); 0b; ()] e a b c ------- 1 0 1 1 2 0 2 2 3 1 0 3 4 2 0 4 5 3 3 0
另外,也可以提前构造好条件列表再传入查询,同样不需要value或eval:
q)conds: {(=;x;0)} each colist q)?[`t; enlist(any; enlist, conds); 0b; ()]
内容的提问来源于stack exchange,提问作者tommylicious
相关产品推荐
相关产品推荐

