kdb+中基于指定列的分隔符动态生成新列的实现方案(避免硬编码索引)
kdb+中基于指定列的分隔符动态生成新列的实现方案(避免硬编码索引)
我太懂你这种硬编码索引的糟心了——一旦text列里的键值对顺序变了,或者某个字段突然缺失,代码直接就崩了,完全不健壮。下面针对你的需求,分场景给你更靠谱的实现方式:
一、动态提取指定键值对(比如country、rank)
从你的代码能看出来,text列的格式是key=value用;分隔(还可能带空格),核心思路是把这种字符串转成字典,之后直接通过键名取值,完全不用管它在第几个位置。
步骤拆解(先单条测试)
假设text的一条数据是:"rank=1; country=Canada; city=Toronto"
- 按
;分割成键值对数组:
q)kvPairs: ";" vs "rank=1; country=Canada; city=Toronto" q)kvPairs "rank=1" " country=Canada" " city=Toronto"
- 清理空格并分割键和值:
q)cleanKv: {raze(" *";"=")0:string x} each kvPairs q)cleanKv (`rank;"1";`country;"Canada";`city;"Toronto")
- 转成字典(键值一一对应):
q)kvDict: flip 2 cut cleanKv q)kvDict rank| "1" country| "Canada" city| "Toronto"
现在直接用kvDict[country]或kvDict[rank]就能拿到对应值,和位置完全无关!
整合到表的更新语句里
我们可以封装成通用函数,方便重复调用:
// 定义通用函数:从text字符串中提取指定键的值 getKvValue: {[textStr; targetKey] if[null textStr; return ::]; // 处理空值情况 kvPairs: ";" vs textStr; // 清理空格+分割键值,过滤空的键值对 cleanKv: raze each (" *";"=")0:string each where not null each kvPairs; kvDict: flip 2 cut cleanKv; kvDict[targetKey] // 直接按键取值 }; // 给表tab新增country和rank列 res: update country: getKvValue[text; `country]; rank: `$getKvValue[text; `rank] // 转成符号类型 from tab;
这个版本就算某个字段缺失,只会返回空值::,不会直接报错,容错性强太多。
二、分割text后展开为行并生成rank序号
如果你的需求是把text列按;分割后,每个元素单独成一行,同时给每行分配从1开始的rank序号,可以用ungroup结合序号生成来实现:
// 先给每行的分割结果生成序号,再展开成多行 res: ungroup update rank: 1+enumerate each count each ";" vs text; // 1开始的序号 splitText: ";" vs text from tab;
解释:enumerate each count each ...会给每个分割后的元素生成从0开始的序号,加1就是从1开始的rank。不管分割出多少个元素,rank都会自动对应,完全不用硬编码数量。
额外小技巧
如果text里的键名大小写不固定(比如有时是Country有时是country),可以在生成字典前统一转成小写:
cleanKv: raze each (" *";"=")0:string each kvPairs; cleanKv[0::2]: lower each cleanKv[0::2]; // 所有键转小写
这样调用函数时用getKvValue[text; country]`就能匹配到各种大小写的键了。
备注:内容来源于stack exchange,提问作者BlackPearl
相关产品推荐
相关产品推荐

