如何在KDB+ Q中按规则生成Run-ID迭代列?
问题描述
现有如下KDB+数据表:
t:([] A:99 99 99 99 99 99 99 99 99 99 99 80 80 80; B:`newcol`newcol`newcol`newcol`newcol`newcol`newcol`newcol`newcol`newcol`newcol`newcol2`newcol2`newcol; Run:`Start`Start`Start`During`During`End`End`End`Start`During`End`Start`End`End)
表格展示:
| A | B | Run |
|---|---|---|
| 99 | newcol | Start |
| 99 | newcol | Start |
| 99 | newcol | Start |
| 99 | newcol | During |
| 99 | newcol | During |
| 99 | newcol | End |
| 99 | newcol | End |
| 99 | newcol | End |
| 99 | newcol | Start |
| 99 | newcol | During |
| 99 | newcol | End |
| 80 | newcol2 | Start |
| 80 | newcol2 | End |
| 80 | newcol | End |
需要生成Run-ID列,规则如下:
- 一个Run以
Start开头,以End结尾; - 同一
A列值下,开头连续的Start属于同一Run,ID保持一致直到Run结束; - 仅在
End之后出现Start时才生成新ID,连续End时ID保持不变。
期望结果:
| A | B | Run | Run-ID |
|---|---|---|---|
| 99 | newcol | Start | 99-1 |
| 99 | newcol | Start | 99-1 |
| 99 | newcol | Start | 99-1 |
| 99 | newcol | During | 99-1 |
| 99 | newcol | During | 99-1 |
| 99 | newcol | End | 99-1 |
| 99 | newcol | End | 99-1 |
| 99 | newcol | End | 99-1 |
| 99 | newcol | Start | 99-2 |
| 99 | newcol | During | 99-2 |
| 99 | newcol | End | 99-2 |
| 80 | newcol2 | Start | 80-1 |
| 80 | newcol2 | End | 80-1 |
| 80 | newcol | End | 80-1 |
解决方案
可以通过KDB+的分组、累计计数和填充逻辑实现,代码如下:
// 按A分组处理每组的Run序列,生成Run-ID列 update Run-ID:string[A],"-",string each { // 标记新Run的触发点:前一行是End且当前是Start,或分组首行是Start flag:0b, (prev x)=`End, x=`Start; // 累计生成Run编号,仅在触发点处递增 runNum:scan {y+1f*z} 1f, flag[1:]; // 向下填充编号,确保后续行继承当前Run的ID fill runNum }[Run] by A from t
执行上述代码后,即可得到符合要求的结果表。
逻辑解释
- 分组隔离:通过
by A按唯一标识符分组,保证每个A的Run序列独立计算ID; - 触发点标记:生成
flag序列,精准定位需要开启新Run的位置——仅当End之后出现Start,或是分组内第一个Start时标记为真; - 编号累计:用
scan对标记序列进行累计计数,每次遇到触发点时编号加1,其他位置保持当前编号; - 填充补全:使用
fill函数将编号向下传递,确保During阶段和连续的End阶段都继承当前Run的编号; - 格式拼接:将A的字符串形式与Run编号拼接成
A-N的格式,得到最终的Run-ID。
内容的提问来源于stack exchange,提问作者user21142340
相关产品推荐
相关产品推荐

