KDB+ 中列表的所有子集

all subsets of lists in KDB+

我是 KDB 新手。我有一个 table 格式如下:

id        date  name  order
34  2020.01.20  John     10
23  2020.01.20  John    -20
21  2020.01.20  John     30
43  2020.01.20  John   -400
44  2020.01.20   Dan  -6483  
22  2020.01.20   Dan   8796

示例table可以创建如下:

t:([]id:(34, 23, 21, 43, 44, 22); date:(2020.01.20; 2020.01.20; 2020.01.20; 2020.01.20; 2020.01.20; 2020.01.20); name:(`John`John`John`John`Dan`Dan); order:(10, -20, 30, -400, -6483, 8796));

我想要以下格式的任何给定 datename 的所有可能的订单子集。现在下面的 order 列是 idorder 值和所有 ids.

的总和
id        date  name  order    ids
34  2020.01.20  John     10     0n
34  2020.01.20  John    -10     23
34  2020.01.20  John     40     21
34  2020.01.20  John   -390     43
34  2020.01.20  John     20     23, 21
34  2020.01.20  John   -360     21, 43
34  2020.01.20  John   -380     23, 21, 43
23  2020.01.20  John    -20     0n
23  2020.01.20  John    -10     34
23  2020.01.20  John     10     21
23  2020.01.20  John   -420     43
23  2020.01.20  John     20     34, 21
23  2020.01.20  John   -390     21, 43
23  2020.01.20  John   -380     34, 21, 43
21  2020.01.20  John     30     0n
21  2020.01.20  John     40     34
21  2020.01.20  John     10     23
21  2020.01.20  John   -370     43
21  2020.01.20  John     20     34, 23
21  2020.01.20  John     20     23, 43
21  2020.01.20  John   -380     34, 23, 43
43  2020.01.20  John   -400     0n
43  2020.01.20  John   -390     34
43  2020.01.20  John   -420     23
43  2020.01.20  John   -370     21
43  2020.01.20  John   -410     34, 23
43  2020.01.20  John   -390     23, 21
43  2020.01.20  John   -380     34, 23, 21
44  2020.01.20   Dan  -6483     0n
44  2020.01.20   Dan   2313     22
22  2020.01.20   Dan   8796     0n
22  2020.01.20   Dan   2313     44

不确定这是否是最佳解决方案,但下面的代码片段将满足您的需求:

orderMap: (!) . t`id`order;  
subsets: ungroup
  update ids: {x where each (count[x]-1){x cross 01b}/01b} each ids from 
  select ids: id by name from t;
t: ej[`name;t;subsets];
t: delete from t where id in' ids;
t: update order: order + sum each orderMap@/:ids from  t;
t

为了保持一致性,将 ids 列创建为整数列表的列表,并使用空数组 `long$() 而不是 0n

更详细:

  1. orderMap: (!) . t`id`order 给出 id-to-order 映射。这里我假设 ids 是唯一的。
  2. subsets 是分配给名称的 nameid 个子集中的 table。 {(count[x]-1){x cross 01b}/01b} returns “包含”有助于形成子集的标志,例如0000b, 1000b, 0100b, ...。可以用整数二进制表示更有效地完成。
  3. ej[`name;t;subsets] - 按名称加入原始 table 与 id 子集。
  4. delete from t where id in' ids 删除 id 包含在 ids 子集中的行。
  5. update order: order + sum each orderMap@/:ids from t 使用 orderMap
  6. 求和 idids' 子集的顺序

虽然此方法有一个您似乎排除的额外组合(如果需要,您可以在之后排除这些),这让您成为了一部分:

q)comb:{$[type b:(count[a:x except y]-1)(01b cross)/01b;(`long$();a);a where each b]};
q)update sum each order from ungroup ungroup select id,order:(order,/:'order i?comb[i]each i),ids:id i?comb[i]each i by date,name from t
date       name id order ids
---------------------------------
2020.01.20 Dan  44 -6483 `long$()
2020.01.20 Dan  44 2313  ,22
2020.01.20 Dan  22 8796  `long$()
2020.01.20 Dan  22 2313  ,44
2020.01.20 John 34 10    `long$()
2020.01.20 John 34 -390  ,43
2020.01.20 John 34 40    ,21
2020.01.20 John 34 -360  21 43
2020.01.20 John 34 -10   ,23
2020.01.20 John 34 -410  23 43
2020.01.20 John 34 20    23 21
2020.01.20 John 34 -380  23 21 43
2020.01.20 John 23 -20   `long$()
2020.01.20 John 23 -420  ,43
...