playbook/docs/tsl/syntax/12_matrix_and_collections.md

8.6 KiB

TSL 数组、键表、矩阵样数据与集合运算

文档类型:语法主线 是否可直接用于生成代码:是 是否含可直接照写示例:是 是否含不可照写反例:否 遇到不确定时:先按本页候选页继续判断;13_resultset_and_filters.md22_matrix_deep_dive.md23_fmarray.md14_ts_sql.md;仍不命中时回到语法路由中心 index.md;如果问题已经超出语法层,回到 TSL 总入口 ../index.md

这一篇收拢 array(...) 的扩展用法:顺序数组、字符串键表、嵌套数组、本页明确的矩阵样比较,以及 in / sqlin / union2 / intersect / minus / outersect 这类去重型集合关系。

本篇职责

回答“array(...) 在 TSL 里除了最普通的一维数组,还能怎样组织数据;哪些矩阵样写法属于本页文档明确形态;元素、子集、整行和行集合关系应该怎样判断”。

智能体数组/矩阵样数据判断流程

  1. 先判断需要顺序数组、字符串键表、嵌套数组、矩阵样比较,还是去重型集合关系。
  2. 普通容器优先从 array(...) 起手;下标和键访问回看值语法页。
  3. 矩阵链式比较只照 :: 系列文档明确示例写,不要混用标量链式比较。
  4. 基础成员判断用 in / not in;整行存在判断用 sqlin / not sqlin;去重型行集合并、交、差、对称差用 union2 / intersect / minus / outersect
  5. 结果集过滤或 TS-SQL 查询需求分别跳转到 13_resultset_and_filters.md14_ts_sql.md
  6. 没有对应代码块时不要发明数组/矩阵样数据/集合关系写法。

核心规则

  • array(...) 既可以写顺序数组,也可以写字符串键表。
  • 顺序数组下标从 0 开始;字符串仍然从 1 开始。
  • array(...) 可以继续嵌套,形成二维或矩阵样数据。
  • 矩阵链式比较 ::>::<::<>::==::>=::<= 属于本页文档明确形态。
  • in / not in 处理的是元素存在关系,以及左侧为数组时的子集关系。
  • sqlin / not sqlin 处理的是行存在关系;左侧要当成一整行去匹配右侧结果集。
  • union2intersectminusoutersect 都按“行”运算,而不是按单元格逐个运算。
  • 集合运算结果会折叠重复行;如果需求是保留重复记录,改看 13_resultset_and_filters.md
  • 当数据本身就是一维数组时,按行集合运算和按元素集合运算是一致的。
  • 左侧是数组时,先判定需求语义:子集关系用 in,整行存在关系用 sqlin

可直接照写示例

基础数组与键表

顺序数组与字符串键表:

代码块身份:可直接照写示例

arr := array(10, 20, 30);
hash := array("Code": "0001", "Price": 12.3);
writeLn("ARR0=", arr[0]);
writeLn("ARR1=", arr[1]);
writeLn("HASH=", hash["Code"]);

结果说明:

  • arr[0] = 10
  • arr[1] = 20
  • hash["Code"] = "0001"

嵌套数组:

代码块身份:可直接照写示例

[r1, r2] := array((1, 2), (3, 4));
writeLn(r1[0]);
writeLn(r1[1]);
writeLn(r2[0]);
writeLn(r2[1]);

结果说明:

  • 依次输出 1234
  • 说明 array((1, 2), (3, 4)) 这种嵌套数组写法可以按普通数组继续读取

代码块身份:输出片段

1
2
3
4

矩阵样比较

矩阵链式比较:

代码块身份:可直接照写示例

r := array(1, 2, -1) ::< array(2, 1, 0) ::< array(3, 2, 1);
writeLn(r[0]);
writeLn(r[1]);
writeLn(r[2]);
s := array(1, 2, -1) ::< 2 ::< array(3, 2, 1);
writeLn(s[0]);
writeLn(s[1]);
writeLn(s[2]);

结果说明:

  • array(1, 2, -1) ::< array(2, 1, 0) ::< array(3, 2, 1) 的三个元素依次输出 101
  • array(1, 2, -1) ::< 2 ::< array(3, 2, 1) 的三个元素依次输出 100
  • 说明矩阵链式比较会按元素位置分别得到结果数组,并且可以和标量混用

innot insqlinnot sqlin

in 既可以判断单个元素是否存在,也可以判断左侧数组是否是右侧结果集的子集:

代码块身份:可直接照写示例

writeLn(1 in array(1, 2, 2));
writeLn(1 in array(0, 2));
writeLn(1 in array((1), (2)));
writeLn(array(1, 2) in array(1, 2, 3, 4));
writeLn(array(1, 3) in array((1, 2), (3, 4)));
writeLn(array(1, 2) in array(1));
writeLn(1 not in array(0, 2));

结果说明:

  • 1 in array(1, 2, 2) 输出 1
  • 1 in array(0, 2) 输出 0
  • 1 in array((1), (2)) 输出 1
  • array(1, 2) in array(1, 2, 3, 4) 输出 1
  • array(1, 3) in array((1, 2), (3, 4)) 输出 1
  • array(1, 2) in array(1) 输出 0
  • 1 not in array(0, 2) 输出 1

代码块身份:输出片段

1
0
1
1

sqlin 按整行判断左侧是否存在于右侧结果集中:

代码块身份:可直接照写示例

writeLn(1 sqlin array(1, 2));
writeLn(array(1, 2) sqlin array(1, 2, 3));
writeLn(array(1, 2) sqlin array((1, 2), (3, 4)));
writeLn(array(5, 6) not sqlin array((1, 2), (3, 4)));

结果说明:

  • 1 sqlin array(1, 2) 输出 1
  • array(1, 2) sqlin array(1, 2, 3) 输出 0
  • array(1, 2) sqlin array((1, 2), (3, 4)) 输出 1
  • array(5, 6) not sqlin array((1, 2), (3, 4)) 输出 1
  • in 看元素或子集
  • sqlin 看整行

行集合并、交、差、对称差

下面这组最小例子展示“按行运算”和“结果会折叠重复行”:

代码块身份:可直接照写示例

left_rows := array((1, 2), (1, 2), (2, 3));
right_rows := array((1, 2), (3, 4));
union_rows := left_rows union2 right_rows;
intersect_rows := left_rows intersect right_rows;
minus_rows := left_rows minus right_rows;
outersect_rows := left_rows outersect right_rows;

结果说明:

  • left_rows union2 right_rows 共有三行:(1,2)(2,3)(3,4)
  • left_rows intersect right_rows 只有一行:(1,2)
  • left_rows minus right_rows 只有一行:(2,3)
  • left_rows outersect right_rows 有两行:(2,3)(3,4)
  • left_rows 原本有两行相同的 (1,2),但 union2 / intersect 的结果都只保留一份,说明集合运算会折叠重复行

更大的四列结果集文档结果:

  • array((1,2,3,4),(2,3,4,5),(1,1,1,1)) union2 array((1,2,3,4),(3,4,5,6),(2,2,2,2)) 返回 array((1,2,3,4),(2,3,4,5),(1,1,1,1),(3,4,5,6),(2,2,2,2))
  • 同一组输入下: intersect 返回 array((1,2,3,4))
  • 同一组输入下: minus 返回 array((2,3,4,5),(1,1,1,1))
  • 同一组输入下: outersect 返回 array((2,3,4,5),(1,1,1,1),(3,4,5,6),(2,2,2,2))

和过滤运算的区别

  • 集合运算先把数据当成“行集合”来看,再做包含、并交差。
  • 过滤运算先保留“原结果集里的每一条命中记录”;因此重复行会保留下来。
  • 需要“集合关系”时留在本页。
  • 需要“从原表里筛出哪些行”时看 13_resultset_and_filters.md

默认生成模板

按需求语义从下面两种模板中选择:

代码块身份:可直接照写示例

matched := 1 in array(1, 2, 3);
row_matched := array(1, 2) sqlin array((1, 2), (3, 4));

本页不生成的范围

  • 专门的结果集过滤函数
  • TS-SQL 查询与写回
  • 更大范围的矩阵函数族

这些内容分别进入 13_resultset_and_filters.md14_ts_sql.md22_matrix_deep_dive.md23_fmarray.md,不再外跳到原目录。

禁止项

  • 不要把字符串下标按数组的 0 起始规则来写;字符串索引回看 03_values_and_literals.md
  • 不要把矩阵链式比较 ::... 和标量链式比较混写成同一种语法。
  • 不要把 insqlin 当成同一个概念。
  • 不要期待 union2 保留重复行。
  • 不要用集合运算去做“保留原始重复记录”的过滤任务。
  • 不要把二维结果集默认当成“按元素逐个比较”的集合运算。
  • 左侧数组要表达“这些值是否都属于右侧集合”时,用 in
  • 左侧数组要表达“这一整行是否存在于右侧结果集”时,用 sqlin
  • minus 表达集合差集;如果任务要求保留左侧原始重复次数,改走 13_resultset_and_filters.md 的过滤规则。
  • 不要在本页发明结果集过滤、TS-SQL 查询、写回语法或更大矩阵函数族。
  • 不要把普通 array(...) 自动升级成 FMArray;只有任务明确命中时才进入 23_fmarray.md