聚合与集合函数
聚合函数 sum、avg、max、min、count、groupConcat、rank 的语法、参数与返回值,以及集合上的 map、filter、sort、group 等扩展方法。
概述
聚合函数把一组值合并成一个值:求和、平均、最大、最小、计数、拼接和名次。报表里最常见的用法是在汇总格中引用一个向下扩展的单元格,例如合计格写 sum(B2),B2 是数据列所在格,引用它会得到该列扩展出的全部值(单元格引用规则见 报表基本语法)。
本篇包含 7 个函数(sum、avg、max、min、count、groupConcat、rank),以及集合对象上的扩展方法(filter、map、sort、group 等)。
功能入口
- 汇总格:在需要放合计的单元格设为「公式」类型,「内容公式」里写
sum(B2)之类的表达式。 - 表达式编辑器右侧「函数」标签页可搜索并插入这些函数。
- 报表上的「合计」也可以用单元格数据设置里的聚合方式实现,无需写公式。
两种调用形态
sum、avg、max、min、count 各有两套实现,调用时按参数个数自动选择:
| 写法 | 适用场景 | 行为 |
|---|---|---|
单个参数:sum(B2)、sum(list) |
参数是单元格引用、集合或数组 | 对集合内元素聚合;无法解析为数字的元素忽略;整体为 null 返回 null(count 返回 0) |
多个参数:sum(1, 2, 3) |
直接列出若干个值 | 参数中的集合会被展开一层;null 被忽略;非数字文本会报错;结果去除末尾 0 |
两种形态的细节在各函数的「说明」里分别给出。
函数详解
sum
语法
sum(collection)
sum(value1, value2, ...)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection |
集合/数组/单个值 | 是(单参数形态) | 要求和的一组值,通常是单元格引用;null 返回 null |
value1, value2, ... |
Object | 是(多参数形态) | 任意个数值或集合 |
返回值:BigDecimal 或 Double;没有任何有效数值时返回 null。
示例
sum(1, 2, 3)
结果:6
sum([1, 2.5, null, 'x'])
结果:3.5(null 与 'x' 被忽略)
sum(B2)
结果:B2 扩展出的全部值之和
说明
- 单参数形态:元素不超过 10 个,或元素中含 BigDecimal 时,按 BigDecimal 累加,返回 BigDecimal;元素超过 10 个且没有 BigDecimal 时,按 double 累加,返回 Double。无法解析为数字的元素(包括文本
"abc"、带千分位的"1,234")被忽略。 - 单个单元格引用只有一个值时,
sum(B2)就是该值本身。 - 多参数形态:传入非数字文本(如
sum(10, 'x'))抛出「不能将 x 转换为数字」错误;结果经过去除末尾 0 处理,整百、整千的值内部表示为科学计数法(如100为1E+2),需要固定小数位时用formatNumber。 - 汇总类公式常见写法:
sum(B2) / count(B2)、A1 / sum(A1[!0])(占全体比例,A1[!0]见 报表基本语法)。
avg
语法
avg(collection)
avg(value1, value2, ...)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection |
集合/数组/单个值 | 是(单参数形态) | 要求平均的一组值;null 返回 null |
value1, value2, ... |
Object | 是(多参数形态) | 任意个数值或集合 |
返回值:BigDecimal 或 Double;没有任何有效数值时返回 null。
示例
avg(1, 2)
结果:1.5
avg([1.0, 2.0])
结果:1.5
avg([1, 2])
结果:2(注意,见说明)
说明
- 多参数形态:中间结果保留 32 位小数,四舍五入后去除末尾 0,
avg(1, 2)为1.5。 - 单参数形态:集合元素不超过 10 个(或含 BigDecimal)时,商的小数位数取各元素中最大的小数位数,整数元素的平均值会被舍入为整数:
avg([1, 2])为2而不是1.5。数据集数值列若为带小数位的 DECIMAL 则位数随列。要精确平均,请用sum(B2) / count(B2)并自行round,或先把列转为带小数的类型。 - 单参数形态:元素超过 10 个且没有 BigDecimal 时按 double 求平均,返回 Double。
- 无法解析为数字的元素被忽略,且不计入分母。
max
语法
max(collection)
max(value1, value2, ...)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection |
集合/数组 | 是(单参数形态) | 要取最大值的一组值;null 返回 null |
value1, value2, ... |
Object | 是(多参数形态) | 任意个数值或集合 |
返回值:单参数形态:集合中最大的元素,保持元素原有类型;多参数形态:BigDecimal。集合为空或全部为 null 时返回 null。
示例
max(1, 5, 3)
结果:5
max([3, 9, 4])
结果:9
说明
- 单参数形态可比较数值、日期和文本(按字典序);多参数形态要求都能转成数字,否则报错。
- 多参数形态结果经过去除末尾 0 处理。
min
语法
min(collection)
min(value1, value2, ...)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection |
集合/数组 | 是(单参数形态) | 要取最小值的一组值;null 返回 null |
value1, value2, ... |
Object | 是(多参数形态) | 任意个数值或集合 |
返回值:单参数形态:集合中最小的元素,保持元素原有类型;多参数形态:BigDecimal。集合为空或全部为 null 时返回 null。
示例
min(4, 2, 8)
结果:2
min([3, 9, 4])
结果:3
说明
- 规则同
max。
count
语法
count(collection)
count(value1, value2, ...)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
collection |
集合/数组/单个值 | 是(单参数形态) | 要计数的对象 |
value1, value2, ... |
Object | 是(多参数形态) | 任意个值或集合 |
返回值:int。
示例
count([10, 20, 30])
结果:3
count(1, null, 3)
结果:2
count(B2)
结果:B2 扩展出的值的个数
说明
- 单参数形态:
null得0;集合或数组得元素个数(包含元素为null的项);单个非集合值得1;Map 得1。 - 多参数形态:
null参数不计;集合参数按其元素个数累加;其余每个值计 1。 count统计的是个数,不是不同值的个数,没有去重计数函数;需要去重个数时可用distinct方法,如B2.distinct().size()。
groupConcat
语法
groupConcat(target)
groupConcat(target, separator)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
target |
集合/数组/单个值 | 是 | 要拼接的一组值;null 返回 null |
separator |
String | 否 | 分隔符,省略时为 , |
返回值:String。
示例
groupConcat(['内科', '外科'], '、')
结果:"内科、外科"
groupConcat(B2)
结果:B2 各值以逗号连接
说明
- 元素为
null时以文本null参与拼接;拼接前需要过滤空值时,先用集合的filter方法。
rank
语法
rank(values, current)
rank(values, current, direction)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
values |
集合 | 是 | 整组值,通常写成组引用 A1[!0] |
current |
数值 | 是 | 当前值,通常写成裸引用 A1;必须是单个值 |
direction |
String | 否 | 排序方向:desc 或 降序(默认,大的排第 1);asc 或 升序(小的排第 1);不区分大小写、忽略首尾空格,空字符串按降序 |
返回值:Integer,名次,从 1 开始;current 不是数字时返回 null(单元格留空)。
示例
rank(A1[!0], A1)
结果:A1 列中本行值的名次,数值最大的为 1
rank(A1[!0], A1, 'asc')
结果:数值最小的为 1
rank([90, 85, 85, 70], 85)
结果:2
说明
- 并列采用竞争排名:并列同名次,之后跳号。
[90, 85, 85, 70]中两个 85 都是第 2,70 是第 4。 values中无法解析为数字的项(如「合计」文本、null)被忽略,不会导致报错。- 排名范围是整张报表中该单元格扩展出的全部值,不分组,暂时无法表达「本科室内排名」。
- 第一个参数必须是组引用
A1[!0]:在扩展行里裸写A1只得到本行的单个值,名次会恒为 1。第二个参数如果是一组值(例如把公式写在合计行)会报错,公式应写在扩展行内。 direction写成其他值(如拼错的acs)会报错,不会静默按降序处理。
集合上的扩展方法
集合(List)和数组上可以直接用点号调用下列方法。带回调的方法,回调写成 (参数) => 表达式。方法返回新的集合(与原集合类型一致),不修改原集合,push 与 each 例外。
| 方法 | 回调参数 | 说明 | 示例 | 结果 |
|---|---|---|---|---|
filter(fn) |
(item, index, size) |
保留回调结果为真的元素 | [1, 2, 3, 4].filter((x) => x > 2) |
[3, 4] |
map(fn) |
(item, index, size) |
转换每个元素 | [1, 2, 3].map((x) => x * 2) |
[2, 4, 6] |
each(fn) |
(item, index, size) |
逐个执行回调(可修改元素),返回原元素集合 | list.each((x) => { x.flag = 1 }) |
元素被修改 |
find(fn) |
(item, index, size) |
第一个回调为真的元素,找不到为 null |
[1, 5, 9].find((x) => x > 3) |
5 |
findIndex(fn) |
(item, index, size) |
第一个匹配元素的位置,找不到为 -1 |
[1, 5, 9].findIndex((x) => x > 3) |
1 |
findNotNull() |
无 | 第一个不为 null 的元素 |
[null, 2].findNotNull() |
2 |
every(fn) |
(item, index) |
是否全部满足 | [2, 4].every((x) => x % 2 == 0) |
true |
some(fn) |
(item, index) |
是否至少一个满足 | [1, 4].some((x) => x % 2 == 0) |
true |
sort(fn) |
(a, b) |
按比较函数排序 | [3, 1, 2].sort((a, b) => a - b) |
[1, 2, 3] |
reserve() |
无 | 反转顺序(方法名就是 reserve) |
[1, 2, 3].reserve() |
[3, 2, 1] |
shuffle() |
无 | 随机打乱 | [1, 2, 3].shuffle() |
随机顺序 |
distinct() / distinct(fn) |
(item) |
去重,可按回调结果去重 | [1, 1, 2].distinct() |
[1, 2] |
join(sep) / join() |
无 | 用分隔符拼接,省略为逗号 | ['a', 'b'].join('-') |
"a-b" |
reduce(fn) |
(acc, item) |
累积计算;空集合得 null,单元素得该元素 |
[1, 2, 3].reduce((a, b) => a + b) |
6 |
group(fn) / group(fn, mapping) |
(item) |
按回调结果分组,返回 Map;第二个回调对每组的列表做转换 | list.group((x) => x.dept) |
{科室: [记录...]} |
toMap(keyFn) / toMap(keyFn, valueFn) |
(item, index, size) |
转为 Map,省略 valueFn 时值为元素本身 |
list.toMap((x) => x.id) |
{id: 记录} |
join(other, condition) |
(left, right) |
类似 SQL 左连接:每个左元素匹配右集合中第一个满足条件的元素,合并两个 Map | a.join(b, (l, r) => l.id == r.id) |
合并后的列表 |
skip(n) / limit(n) |
无 | 跳过前 n 个 / 只取前 n 个 | [1, 2, 3].skip(1) |
[2, 3] |
first() / last() |
无 | 第一个 / 最后一个元素,空集合为 null |
[1, 2, 3].last() |
3 |
size() |
无 | 元素个数 | [1, 2, 3].size() |
3 |
push(item) |
无 | 向集合末尾追加(传入集合则逐个追加),返回集合本身 | list.push(x) |
集合被修改 |
concat(other, ...) |
无 | 合并多个集合,返回新集合 | [1].concat([2], [3]) |
[1, 2, 3] |
sum() / avg() / max() / min() |
无 | 只统计数字元素;sum 与 avg 返回 double 数值 |
[1, 2, 3].sum() |
6.0 |
说明
sort的比较函数返回值被取整(截断小数)后决定顺序:(a, b) => a.amount - b.amount在两个金额相差小于 1 时会被视为相等。金额带小数时先放大,或改用sort之外的方式。- 没有
size之外的length属性调用;字符串长度用函数length(str)。 - 单元格引用
B2得到的是 List 时可直接调用这些方法,例如B2.filter((x) => x > 100).size()。当引用只有一个值时得到的是该值本身而不是 List,此时集合方法不可用,需要稳定得到集合时,用A1[!0](恒为 List)。
注意事项
注意:一个单元格引用的返回形态不固定:多个值时是 List,只有一个值时是该值本身。聚合函数(
sum、count等)两种形态都能处理,但集合方法(filter、map等)只能用于 List。
注意:
count不会忽略集合里的null元素,单参数形态下count([1, null, 3])为3;count(1, null, 3)(多参数形态)为2。
提示:汇总求和优先使用单元格数据设置里的聚合方式;只有在需要与其他单元格再运算时才写
sum(...)公式。