Ninox 中的数组

简单数组

操作文本或数字数组非常直接:

var myArray := ["a", "b", "d"];

index(myArray, "b");
myArray := array(myArray, ["c"]);

myArray order this;

对文本或数字数组,也可以使用 ordersortunsort 进行排序。
更多与数组相关的函数,请参阅 Ninox 文档

二维数组

Ninox 不直接支持二维数组。作为替代,可以使用由 JSON 对象组成的数组。
例如,按 d2 字段的第二个元素对数组排序:

var myArray := [{'d2':["a", "Z"]}, {'d2':["b", "B"]}, {'d2':["c", "C"]}, {'d2':["d", "D"]}];

(myArray order by item('d2', 1));

这段代码返回:[{"d2":["b","B"]},{"d2":["c","C"]},{"d2":["d","D"]},{"d2":["a","Z"]}]

筛选数组

您可以像筛选 select 的结果那样筛选数组。对于文本或数字数组,用 this 指代正在被筛选的值:

var myArray := ["Jan", "Fred", "Jacques"];
myArray[this like "J"] order this;

对于 JSON 数组,则直接使用键名:

var myArray := [
  { 'prénom' : "Jan", nom : "Augustin" },
  { 'prénom' : "Fred", nom : "Baillot" },
  { 'prénom' : "Jacques", nom : "Tur" }
];

myArray[nom like "i"] order 'prénom';

这段代码返回一个 JSON 数组:[{"prénom":"Fred","nom":"Baillot"}, {"prénom":"Jan","nom":"Augustin"}]

对 JSON 数组执行自定义操作

对于 JSON 数组,您可以加入一个代码块(放在圆括号中),为每一次迭代执行自定义操作。与 for in 一样,结果数组的类型取决于代码块中最后一行代码。

示例:计算全名(prénom + nom)的长度:

var myArray := [
  { 'prénom' : "Leo", nom : "Martin" },
  { 'prénom' : "Paul", nom : "Garnet" },
  { 'prénom' : "Pierre", nom : "Dur" }
];

var nameLengths := myArray[nom like "a"].(
    var fullName := ---{'prénom'} {nom}---;
    length(fullName)
);
nameLengths;

这段代码返回一个数字数组 [10, 11],表示这些全名的长度。

初始化一个带类型的空数组

在 Ninox 中,创建仍然带有正确记录类型的空数组的惯用技巧,是执行一个带 where false 过滤条件的 select
该查询返回零条记录,但保留了数组元素的类型。

"Empty Invoice Item array:";
let t := (select 'Invoice Item' where false);
  • 现在 t 是一个数组,其元素为 Invoice Item 类型。
  • 因为它虽为空却带有类型,可以放心地用作 array() 操作的起点。

为什么不直接用 []

字面量 [] 是一个无类型数组。它通常能用,但当与记录集合上的 array() 结合使用时,Ninox 可能会报告类型不一致。
select … where false 这种写法可以彻底避开这个问题。

为基本类型(数字、文本、JSON……)创建空数组

当您需要一个存放标量值(数字、文本字符串或 JSON 对象)的空数组时,并没有可供 select 的底层表。
不过您仍然可以先用一个占位元素初始化 [],再立刻把它过滤掉,从而得到一个带类型的空数组:

"Empty number / text / JSON array:";
let t := [1][false];   "t is now an empty but number typed array";

[1] 生成一个单元素的数字数组;[false] 过滤器移除该元素,留下一个仍保有数字类型的空数组。
如果需要文本或 JSON 类型,就把 1 换成相应的文本或 JSON 字面量。

把二维数组展平

每张 Invoice 都有自己的 Invoice Items 子数组。要得到一个囊括所有发票全部条目的列表,可以遍历各张发票并把它们的子数组拼接起来。

"Initialize empty array:";
let t := (select 'Invoice Item' where false);

"Iterate over each invoice and add its items:";
for i in Invoices do
    t := array(t, i.'Invoice Items')
end;

"Return the flattened list:";
t

工作原理

  1. for i in Invoices do … end 遍历每一条 Invoice 记录。
  2. array(t, i.'Invoice Items')t 的当前值与该发票中的条目数组拼接起来。
    • 第一轮迭代追加第一张发票的条目。
    • 第二轮迭代追加第二张发票的条目,依此类推。
  3. 循环结束后,t 就在一个扁平数组中包含了所有发票的所有条目。

现在您可以执行 count(t) 之类的操作来了解条目总数,也可以直接对 t 进行循环或筛选。