15 KiB
TSL FMArray
文档类型:语法深水专题 是否可直接用于生成代码:是 是否含可直接照写示例:是 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;22_matrix_deep_dive.md、12_matrix_and_collections.md、14_ts_sql.md;仍不命中时回到语法路由中心 index.md;如果问题已经超出语法层,回到 TSL 总入口 ../index.md
这一篇只讲 FMArray 文档主干能力:怎样构造 FMArray、怎样判断类型、怎样和 Array 互转、怎样读取尺寸、做基础运算、做多维转置与维度交换、做矩阵连接、参与 select/mselect,以及 insert/delete/update 语法边界。
本篇职责
回答“什么时候该用 FMArray 而不是普通 array,以及文档明确 FMArray 写法有哪些”。
智能体 FMArray 判断流程
- 先判断是否确实需要
FMArray,普通数组能解决时先用普通数组。 - 构造、类型判断、尺寸读取、转置、连接和 TS-SQL 参与只照本页文档明确形态写。
insert、delete、update的收尾形式分别判断,不要互相套用。- FMArray 错误边界按本页反例处理,不要凭普通数组经验修写法。
- 没有对应代码块时不要发明 FMArray 写法。
核心规则
fmarray[...]可以直接构造FMArray常量。dataType(v)对FMArray返回27。dataType(v, 1)可以读出FMArray单元格类型;本页文档类型包括0整型、1浮点、2064 位整型。- FMArray 相关函数的参数规格见 ../reference/catalog/system.md 和 ../reference/catalog/math.md;本页只保留 FMArray 行为示例和返回形态边界。
ifFmarray(v)可直接判断值是否为FMArray。mInit、mInitDiag、mRand都可直接生成FMArray。arrayToFm和matrixToArray可在Array/FMArray间互转。msize、mrows、mcols都支持FMArray;对三维FMArray,msize会返回全部维度长度。FMArray支持和标量、FMArray、Array做基础算符运算。union2支持FMArray/Array混合运算;结果类型跟随左值。- 对超过二维的
FMArray,反引号转置会把全部维度倒置;mswap可只交换指定维度。 union可做按行连接且不去重,但列结构必须兼容。|和:|都可做矩阵并右方(按列连接);行数不一致时会用0补齐,并且两者表现一致。- 对
FMArray做普通select不会保留FMArray类型;mselect也不会返回dataType=27。 insert into a array(...)、delete from a where ...;、update a set ... where ... end;都能作用于FMArray,但三者的收尾形式并不完全相同。
可直接照写示例
常量构造与类型判断
代码块身份:可直接照写示例
f1 := fmarray[1, 2, 3];
f2 := fmarray[[1, 2], [3, 4]];
f3 := fmarray[1.0, 2.0, 3.5];
writeLn(dataType(f1));
writeLn(dataType(f1, 1));
writeLn(dataType(f3, 1));
writeLn(ifFmarray(f1));
writeLn(length(f1));
writeLn(f1[0], ',', f1[1], ',', f1[2]);
writeLn(mrows(f2));
writeLn(mcols(f2));
writeLn(f2[0,0], ',', f2[0,1], ',', f2[1,0], ',', f2[1,1]);
结果说明:
dataType(f1)返回27dataType(f1, 1)返回0dataType(f3, 1)返回1ifFmarray(f1)返回1length(f1)返回3f1的三个元素依次是1、2、3f2的行数是2、列数是2f2四个单元依次是1、2、3、4
代码块身份:输出片段
27
0
1
1
mInit、mInitDiag、mRand
代码块身份:可直接照写示例
fm1 := mInit(5, 3);
fm2 := mInit(array(3, 2), 1L);
fd1 := mInitDiag(3, 3, 1);
fr1 := mRand(2, 3);
writeLn(dataType(fm1, 1));
writeLn(length(fm1));
writeLn(fm1[0], ',', fm1[1], ',', fm1[2], ',', fm1[3], ',', fm1[4]);
writeLn(dataType(fm2, 1));
writeLn(mrows(fm2));
writeLn(mcols(fm2));
writeLn(fd1[0,0], ',', fd1[0,1], ',', fd1[1,0], ',', fd1[1,1], ',', fd1[2,2]);
writeLn(mrows(fr1));
writeLn(mcols(fr1));
结果说明:
mInit(5, 3)生成长度为5的整型FMArray,五个元素都是3dataType(fm1, 1)返回0mInit(array(3, 2), 1L)的单元格类型是20fm2的行数是3、列数是2mInitDiag(3, 3, 1)的(0,0)、(1,1)、(2,2)为1,而(0,1)、(1,0)为0mRand(2, 3)的行数是2、列数是3
arrayToFm、matrixToArray 与单元格类型转换
代码块身份:可直接照写示例
a1 := array(1, 2, 3.5);
f1 := arrayToFm(a1, 0);
f2 := arrayToFm(a1, 0.0);
f3 := int64(fmarray[1, 2, 3]);
a2 := matrixToArray(fmarray[[1, 2], [3, 8]]);
writeLn(dataType(f1, 1));
writeLn(f1[0], ',', f1[1], ',', f1[2]);
writeLn(dataType(f2, 1));
writeLn(f2[0], ',', f2[1], ',', f2[2]);
writeLn(dataType(f3, 1));
writeLn(f3[0], ',', f3[1], ',', f3[2]);
writeLn(mrows(a2));
writeLn(mcols(a2));
writeLn(a2[0][0], ',', a2[0][1], ',', a2[1][0], ',', a2[1][1]);
结果说明:
arrayToFm(a1, 0)的单元格类型是0,结果是1,2,3arrayToFm(a1, 0.0)的单元格类型是1,结果是1,2,3.5int64(fmarray[1, 2, 3])的单元格类型是20matrixToArray(fmarray[[1, 2], [3, 8]])返回一个2 x 2的Array,内容是(1,2)、(3,8)
尺寸与重构
二维和三维尺寸:
代码块身份:可直接照写示例
f3 := fmarray[[[1, 1], [2, 2], [3, 3]], [[2, 2], [3, 3], [4, 4]]];
s := msize(f3);
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
结果说明:
msize(f3)的长度是3- 三个维度依次是
2、3、2
reshape 会保持 FMArray 类型:
代码块身份:可直接照写示例
f1 := fmarray[[1, 2], [3, 4], [5, 5]];
r1 := reshape(f1, 6);
writeLn(dataType(r1));
writeLn(length(r1));
writeLn(r1[0], ',', r1[1], ',', r1[2], ',', r1[3], ',', r1[4], ',', r1[5]);
结果说明:
dataType(r1)仍然是27r1的长度是6- 元素依次是
1、2、3、4、5、5
标量运算与基础算符
代码块身份:可直接照写示例
f1 := fmarray[1, 2, 3];
f2 := fmarray[2, 3, 4];
a1 := array(2, 3, 4);
s0 := f1 + 1;
s1 := f1 + f2;
s2 := f1 + a1;
writeLn(dataType(s0));
writeLn(s0[0], ',', s0[1], ',', s0[2]);
writeLn(dataType(s1));
writeLn(s1[0], ',', s1[1], ',', s1[2]);
writeLn(dataType(s2));
writeLn(s2[0], ',', s2[1], ',', s2[2]);
结果说明:
f1 + 1的dataType是27,结果是2,3,4f1 + f2的dataType是27,结果是3,5,7f1 + array(2, 3, 4)的dataType仍是27,结果也是3,5,7
union2 与左值类型
代码块身份:可直接照写示例
f1 := fmarray[1, 2, 0, 4, 5];
a1 := array(1, 0, 7.2);
u1 := f1 union2 a1;
u2 := a1 union2 f1;
writeLn(dataType(u1));
writeLn(dataType(u1, 1));
writeLn(length(u1));
writeLn(u1[0], ',', u1[1], ',', u1[2], ',', u1[3], ',', u1[4], ',', u1[5]);
writeLn(dataType(u2));
writeLn(length(u2));
writeLn(u2[0], ',', u2[1], ',', u2[2], ',', u2[3], ',', u2[4], ',', u2[5]);
结果说明:
union2的结果dataType是27f1 union2 array(1, 0, 7.2)的单元格类型会提升为1浮点型f1 union2 array(1, 0, 7.2)的长度是6,结果是1,2,0,4,5,7.2array(1, 0, 7.2) union2 f1的dataType是5array(1, 0, 7.2) union2 f1的长度也是6,结果是1,0,7.2,2,4,5
多维转置与维度交换
三维 FMArray 上,反引号转置会把全部维度倒置:
代码块身份:可直接照写示例
f3 := fmarray[[[1], [2]], [[1], [0]], [[3], [-8]]];
t := `f3;
s := msize(t);
writeLn(dataType(t));
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
writeLn(t[0,0,0], ',', t[0,0,1], ',', t[0,0,2], ';', t[0,1,0], ',', t[0,1,1], ',', t[0,1,2]);
结果说明:
- 原矩阵尺寸是
3,2,1,转置后尺寸是1,2,3 - 结果
dataType仍是27 - 转置后的内容是
[[[1,1,3],[2,0,-8]]]
只交换指定维度时,使用 mswap:
代码块身份:可直接照写示例
f3 := fmarray[[[1], [2]], [[1], [0]], [[3], [-8]]];
t := mswap(f3, 0, 1);
s := msize(t);
writeLn(dataType(t));
writeLn(length(s));
writeLn(s[0], ',', s[1], ',', s[2]);
writeLn(t[0,0,0], ',', t[0,1,0], ',', t[0,2,0], ';', t[1,0,0], ',', t[1,1,0], ',', t[1,2,0]);
结果说明:
mswap(f3, 0, 1)后尺寸是2,3,1- 结果
dataType仍是27 - 结果内容是
[[[1],[1],[3]],[[2],[0],[-8]]]
矩阵连接 / 矩阵并右方:union、|、:|
union 会按行拼接,不做去重:
代码块身份:可直接照写示例
t1 := fmarray[[1, 2], [3, 4], [5, 5]];
t2 := fmarray[[7, 8]];
u := t1 union t2;
writeLn(dataType(u));
writeLn(mrows(u));
writeLn(mcols(u));
writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1], ';', u[3,0], ',', u[3,1]);
结果说明:
union的结果dataType是27t1 union t2的行数是4、列数是2- 拼接后四行依次是
(1,2)、(3,4)、(5,5)、(7,8)
| 和 :| 会执行矩阵并右方,也就是按列拼接:
代码块身份:可直接照写示例
t1 := fmarray[[1, 2], [3, 4], [5, 5]];
t2 := fmarray[[3, 4], [7, 8], [6, 9]];
u1 := t1 | t2;
u2 := t1 :| t2;
writeLn(dataType(u1));
writeLn(mrows(u1));
writeLn(mcols(u1));
writeLn(u1[0,0], ',', u1[0,1], ',', u1[0,2], ',', u1[0,3]);
writeLn(u1[1,0], ',', u1[1,1], ',', u1[1,2], ',', u1[1,3]);
writeLn(u1[2,0], ',', u1[2,1], ',', u1[2,2], ',', u1[2,3]);
writeLn(u2[0,0], ',', u2[0,1], ',', u2[0,2], ',', u2[0,3]);
writeLn(u2[1,0], ',', u2[1,1], ',', u2[1,2], ',', u2[1,3]);
writeLn(u2[2,0], ',', u2[2,1], ',', u2[2,2], ',', u2[2,3]);
代码块身份:输出片段
27
3
4
1,2,3,4
3,4,7,8
5,5,6,9
1,2,3,4
3,4,7,8
5,5,6,9
结果说明:
|的结果dataType是27t1 | t2和t1 :| t2的行数都是3、列数都是4- 两种写法的结果都依次是
(1,2,3,4)、(3,4,7,8)、(5,5,6,9)
行数不一致时,| 和 :| 在 FMArray 上表现一致,缺失行会用 0 补齐。
代码块身份:可直接照写示例
m1 := fmarray[[1, 2], [3, 4], [5, 5]] | fmarray[[3, 4]];
m2 := fmarray[[3, 4]] | fmarray[[1, 2], [3, 4], [5, 5]];
writeLn(m1[0,0], ',', m1[0,1], ',', m1[0,2], ',', m1[0,3]);
writeLn(m1[1,0], ',', m1[1,1], ',', m1[1,2], ',', m1[1,3]);
writeLn(m1[2,0], ',', m1[2,1], ',', m1[2,2], ',', m1[2,3]);
writeLn(m2[0,0], ',', m2[0,1], ',', m2[0,2], ',', m2[0,3]);
writeLn(m2[1,0], ',', m2[1,1], ',', m2[1,2], ',', m2[1,3]);
writeLn(m2[2,0], ',', m2[2,1], ',', m2[2,2], ',', m2[2,3]);
代码块身份:输出片段
1,2,3,4
3,4,0,0
5,5,0,0
3,4,1,2
0,0,3,4
0,0,5,5
fmarray[[1, 2], [3, 4], [5, 5]] | fmarray[[3, 4]]的结果三行依次是(1,2,3,4)、(3,4,0,0)、(5,5,0,0)fmarray[[3, 4]] | fmarray[[1, 2], [3, 4], [5, 5]]的结果三行依次是(3,4,1,2)、(0,0,3,4)、(0,0,5,5)- 把上面两条里的
|改成:|,结果一致
排序
一维排序:
代码块身份:可直接照写示例
s1 := fmarray[10, 2, -3, 8];
sortArray(s1);
writeLn(s1[0], ',', s1[1], ',', s1[2], ',', s1[3]);
结果说明:
- 排序后结果是
-3,2,8,10
二维按字段排序:
代码块身份:可直接照写示例
f1 := fmarray[[11, 12], [31, 4], [5, 5]];
sortTableByField(f1, 0, 1);
writeLn(f1[0,0], ',', f1[0,1], ';', f1[1,0], ',', f1[1,1], ';', f1[2,0], ',', f1[2,1]);
结果说明:
- 排序后依次是
(5,5)、(11,12)、(31,4)
TS-SQL 对 FMArray 的支持
代码块身份:可直接照写示例
q1 := select * from fmarray[[1, 2], [0, 4], [1, 2], [5, 6]] end;
q2 := mselect * from fmarray[[1, 2], [0, 4], [1, 2], [5, 6]] end;
writeLn(dataType(q1));
writeLn(mrows(q1));
writeLn(dataType(q2));
writeLn(mrows(q2));
writeLn(mcols(q2));
结果说明:
- 普通
select的返回dataType是5 q1的行数是4mselect的返回dataType是17q2的行数是4、列数是2- 说明对
FMArray做 TS-SQL 查询时,结果不会保留dataType=27
insert / delete / update
insert:
代码块身份:可直接照写示例
a := mInit(2, 3, 1.0);
insert into a array(9);
writeLn(mrows(a));
writeLn(mcols(a));
writeLn(a[2,0], ',', a[2,1], ',', a[2,2]);
结果说明:
- 插入后行数是
3 - 列数仍是
3 - 新插入的第三行是
9,9,9
delete:
代码块身份:可直接照写示例
d := fmarray[[1, 2], [0, 4], [5, 6]];
delete from d where [1] = 4;
writeLn(mrows(d));
writeLn(d[0,0], ',', d[0,1], ';', d[1,0], ',', d[1,1]);
结果说明:
- 删除后行数是
2 - 保留的两行是
(1,2)、(5,6)
update:
代码块身份:可直接照写示例
u := fmarray[[1, 2], [0, 4], [5, 6]];
update u set [0] = 100 where [1] = 4 end;
writeLn(mrows(u));
writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1]);
结果说明:
- 更新后行数仍是
3 - 结果三行依次是
(1,2)、(100,4)、(5,6)
这三种写法的收尾形式为:
insert into a array(9);delete from d where [1] = 4;update u set [0] = 100 where [1] = 4 end;
本页不生成的范围
mInitDiag更高维行为mRand的随机分布参数变体union/|/:|与普通array的更多混合边界left join/right join/ 更复杂 SQL 写回- CopyOnWrite 的内存级行为
这些不作为本页可生成事实。
默认生成模板
需要 FMArray 常量时,优先从这个最短模板开始:
代码块身份:可直接照写示例
f := fmarray[1, 2, 3];
禁止项
- 在一个
FMArray常量里混用不同单元格类型。 - 把
FMArray当成支持字符串下标的array。 - 以为对
FMArray做普通select后,结果还是dataType=27。 - 把
delete和update的结尾形式写成同一种。 - 以为
union可以忽略列结构差异。 - 以为
array union2 fmarray还会返回FMArray。
代码块身份:反例 / 不可照写
f := fmarray[1, 2.0, 3];
上面这种写法不作为可写事实,会编译失败,错误信息包含 fmarray must be same type。
代码块身份:反例 / 不可照写
f := fmarray[1, 2, 3];
writeLn(f["A"]);
上面这种写法不作为可写事实,会运行报错,错误信息包含 fmarray index type error。
代码块身份:反例 / 不可照写
delete from d where [1] = 4 end;
这类写法不要直接当成默认模板。delete ... end; 会报 Statement missing terminator;文档明确写法是 delete ...;。
代码块身份:反例 / 不可照写
t1 := fmarray[[1, 2], [3, 4]];
t2 := fmarray[[7, 8, 9]];
u := t1 union t2;
上面这种写法会运行报错,错误信息包含 union dim dismatch。本页明确的 union 只适用于列结构兼容的 FMArray。