跳到主要内容
Varlig 指南
Varlig 首页

列表与统计

列表把多个值集中放在一个名称下,比如一周的步数、一组考试分数或一个月的收据。把值放进列表后,你就可以求和、求平均值、衡量它们的离散程度,并挑出重要的值。

本页介绍如何书写列表和按索引取值、汇总统计、合计上方的行、用标签给行打上标记以便把分散各处的行加总、排序与切片、用 map 和 filter 变换列表,以及对整个列表进行运算。每当你有一列数字需要汇总时,都可以参考本页。由行组成的列表还可以当作矩阵使用,矩阵有专门的页面介绍。

书写列表

把值放在方括号里,用逗号分隔:

calc
成绩 = [72, 85, 91, 64, 88] 结果为 [72, 85, 91, 64, 88]
成绩[0] 结果为 72
成绩[4] 结果为 88
length(成绩) 结果为 5

值在列表中的位置称为索引,写在列表后面的方括号里。索引从零开始,所以 成绩[0] 是第一个分数,成绩[4] 是第五个。最后一个元素总是位于 length(成绩) - 1。负数、小数或超出范围的索引都会报错;索引不会从末尾倒着绕回来。

元素可以是计算式、带单位的数量,也可以是其他列表:

calc
[2 * 45, 60 + 15] 结果为 [90, 75]
[1.5 kg, 750 g] 结果为 [1.5 kg, 750 g]
[[1, 2], [3, 4]][1][0] 结果为 3

对于嵌套列表,第一个索引选出内层列表,第二个索引再从中选出一个值:[1] 选中 [3, 4],然后 [0] 选中 3。

千位分隔符在列表中同样有效,所以你可以按数字原本的写法直接粘贴。在值与值之间的每个逗号后面加一个空格;逗号后面紧跟三位数字时,仍然算作同一个数字的一部分:

calc
工资 = [£32,000, £41,500, £38,250] 结果为 [£32,000.00, £41,500.00, £38,250.00]
average(工资) 结果为 £37,250.00

有几点需要注意:

  • 不加空格时,每个逗号都会分隔值,所以 [8200,10400] 包含两个值。像 [100,200,300] 这样的列表既可能是一个数字,也可能是三个数字,因此 Varlig 会显示错误,并写明两种可能的含义。
  • 结果会显示千位分隔符,并在每个逗号后面加一个空格,所以 [8,200, 10,400] 是包含两个值的列表。
  • 一个列表最多包含 1,024 个值。

汇总统计

calc
成绩 = [72, 85, 91, 64, 88]
sum(成绩) 结果为 400
average(成绩) 结果为 80
median(成绩) 结果为 85
min(成绩) 结果为 64
max(成绩) 结果为 91
count(成绩) 结果为 5

mean 和 avg 是 average 的别名,total 是 sum 的别名,stdev 是 stddev 的别名,count 是 length 的别名,所以电子表格里的习惯写法可以照搬过来。product 把所有值相乘。关于出现最多的值、百分位数和四分位数,请参阅下文。

对于命名的列表,你也可以用文字写出统计量:

calc
成绩 = [72, 85, 91, 64, 88]
average of 成绩 结果为 80
total of 成绩 结果为 400

sum of、mean of、median of、min of、max of 和 count of 的用法相同。在 of 后面写一个名称,或者直接写出用逗号分隔的值,加不加圆括号都可以。如果值写在方括号里,请使用函数形式,如 average([72, 85, 91])。

大多数统计函数,包括 sum、product、average、median、min、max、count 和 stddev,也接受分开书写的值,而不一定是列表:

calc
max(72, 85, 91) 结果为 91
sum(1, 2, 3, 4) 结果为 10
average of 70, 85, 91 结果为 82
mean of (1,2,3) 结果为 2
average(1,200, 1,800) 结果为 1,500

合计上方的行

只写了 sum、total、subtotal、grand total、average、max 或 min 的一行,会对它上方的答案求出相应的数字。它只管自己所在的那一段,这一段从上一个合计行、--- 分隔线或 # 标题开始,所以笔记中的每个部分都能在你输入时得到各自的数字。它的作用与某一行快捷菜单中的 小计(小计)选项相同:

calc
# 食品杂货
面包 = £1.20
牛奶 = £1.45
鸡蛋 = £2.30
total 结果为 £4.95
# 日用品
垃圾袋 = £3.50
洗洁精 = £1.80
total 结果为 £5.30

这个词前面可以加说明文字,也可以给它起个名称、把结果换算成别的单位,或者在后面写注释,这样整行读起来就和笔记的其余部分一样自然:

calc
门票 = £64
火车 = £41.20
预计合计: total 结果为 £105.20

est = total 会把这个数字存进一个名称,total // 还没订 则在旁边加一条注释。total in kg 会先换算再显示,这一段里克和千克混着写时特别有用。统计词写在运算符旁边时,表示它单独成行时会显示的那个数字,所以 £5 + subtotal 就是在当前小计上再加五英镑。

calc
# 包裹
12 kg 结果为 12 kg
4 kg 结果为 4 kg
850 g 结果为 850 g
total in kg 结果为 16.85 kg
max 结果为 12 kg

如果你给某个值起名为 sum 或 total,这一行会显示你的值。如果上方没有可以合计的内容,这一行会显示 Unsupported: no amounts above to add up,而不是留空或显示零——出现这种情况,通常是因为中间有一个你忘了的标题。

每笔金额只计一次。如果这一段里后面的某一行是根据某个命名金额算出来的,合计只算那一行,而不会两笔都算,所以一张写着单价和数量的购物清单加出来的正是你实际要付的钱:

calc
衬衫 = £18.50
短裤 = £9
9 * 衬衫 结果为 £166.50
10 * 短裤 结果为 £90.00
手续费 = £40
增值税 = 手续费 * 20% 结果为 £8.00
total 结果为 £304.50

衬衫 和 短裤 已经计入了用到它们的那两行,而 手续费 仍然留在合计里,因为 增值税 只取了它的一部分。

这条规则会沿着名称一路追溯下去。如果笔记把一笔钱拆成几份、再把这几份加回去,那么加总的那一行会计入,被拆分的那笔金额也会计入:

calc
奖金池 = £900
一等 = 50% of 奖金池 结果为 £450.00
二等 = 30% of 奖金池 结果为 £270.00
三等 = 20% of 奖金池 结果为 £180.00
一等 + 二等 + 三等 结果为 £900.00
total 结果为 £900.00

只有同类的量才会相加。上方有金额或带单位的量时,百分比、比率和普通计数都不会计入,出错的行也一样。粘贴成一列的普通数字,只要像金额那样精确到分位就会计入;小数位更多的(比如汇率或系数)则不会。合计行的提示会点名它略过的每一项,例如“Leaves out line 3 (people = 2)”或“Leaves out line 2 (an error)”,让你一眼看清这个数字包含了什么。

如果紧挨着合计行的上方,有两笔及以上不带名称的金额,而它们上面又有一行是根据名称算出来的,那么只把这几笔不带名称的加起来。这样一来,笔记开头算出的预算就不会在下面的清单里被重复计算:

calc
预算 = £18,000
剩余 = 预算 - £6,388.25 结果为 £11,611.75
- 垃圾清运 £250 结果为 £250.00
- 深度保洁 £120 结果为 £120.00
subtotal 结果为 £370.00

要把并不相邻的行加总,请改用标签给它们打上标记。

最常出现的值

mode 给出出现次数比其他任何值都多的那个值,modes 则以列表形式给出并列出现最多的所有值:

calc
分数 = [3, 4, 4, 5, 5, 5, 6]
mode(分数) 结果为 5
modes([1, 1, 2, 2, 3]) 结果为 [1, 2]

只有当某一个值严格地出现得最多时,mode 才会给出答案。如果没有任何值重复出现,或者几个值并列,它会如实说明,而不会随便挑一个:

calc
mode([1, 2, 3]) 结果为 Unsupported: No value repeats, so this list has no mode; use median or average instead

百分位数与四分位数

percentile(list, rank) 接受一个 0 到 100 之间的名次,给出该处的值,并在最接近的两个观测值之间做线性插值。quartile(list, k) 是它在四分位上的版本,k 取 0 到 4,所以 quartile(list, 1) 就是 percentile(list, 25):

calc
成绩 = [72, 85, 91, 64, 88]
percentile(成绩, 50) 结果为 85
percentile(成绩, 25) 结果为 72
quartile(成绩, 3) 结果为 88
quartile(成绩, 4) 结果为 91
percentile([1, 2, 3, 4], 25) 结果为 1.75
quartile([1, 2, 3, 4], 3) 结果为 3.25

第 50 百分位数就是中位数,第 0 和第 100 百分位数 —— 也就是 quartile(list, 0) 和 quartile(list, 4) —— 是最小值和最大值,与 min 和 max 相同。名次超出范围会报错,而不会退回到最接近的那个合法值:

calc
percentile([1, 2, 3, 4], 101) 结果为 Unsupported: A percentile is between 0 and 100
quartile([1, 2, 3, 4], 5) 结果为 Unsupported: A quartile is 0, 1, 2, 3 or 4

离散程度:方差与标准差

calc
成绩 = [72, 85, 91, 64, 88]
variance(成绩) 结果为 132.5
stddev(成绩) to 1 dp 结果为 11.5

两者都是样本统计量:它们除以值的个数减一(n - 1),当你的数据是从更大整体中抽取的样本时,通常这样计算。它们至少需要两个值。在任何统计量后面加上 to 1 dp 即可舍入。

当你的列表是整个总体、而不是一份样本时,请使用总体形式:它们除以 n,只需要一个值:

calc
# 列车延误分钟数
延误 = [2, 4, 4, 4, 5, 5, 7, 9]
sample_variance(延误) 结果为 4.5714285714
population_variance(延误) 结果为 4
sample_stddev(延误) 结果为 2.1380899353
population_stddev(延误) 结果为 2
调用 平方差的除数 所需的值
variance、sample_variance n - 1 两个
population_variance n 一个
stddev、stdev、sample_stddev n - 1 两个
population_stddev n 一个

sample_variance 和 sample_stddev 是 variance 和 stddev 的长名称,可以用来写明你指的是哪一个。短名称一直都是样本形式,现在依然如此。

带单位的列表

sum、average、median、mode、modes、percentile、quartile、min、max、stddev 和 population_stddev 会保留单位,并在兼容的单位之间换算。这些值按第一个值的单位来读取,答案也以该单位给出:

calc
通勤 = [24 min, 31 min, 27 min, 22 min]
sum(通勤) 结果为 1 hour 44 min
average(通勤) 结果为 26 min
median(通勤) 结果为 25.5 min
percentile(通勤, 25) 结果为 23.5 min
population_stddev(通勤) 结果为 3.3911649916 min
sum([1 kg, 500 g]) 结果为 1.5 kg
modes([1 kg, 500 g, 1 kg, 500 g]) 结果为 [0.5 kg, 1 kg]

方差是个例外:它要对观测值求平方,没有哪个单位能挺过这一步,所以它们只接受普通数字。

calc
sample_variance([1 kg, 2 kg]) 结果为 Unsupported: A variance squares its observations, so it takes plain numbers; use stddev for amounts with a unit

sort 同样只适用于普通数字。对单位不兼容的值(如 sum([1 kg, 3 m]))进行统计会报错,而不会悄悄跳过某些值。

所有这些背后的精确性规则,请参阅引擎作出的保证。

空列表

对空列表调用 结果
sum([]) 0
product([]) 1
count([]), length([]) 0
average([]), median([]), min([]), max([]) 错误
variance([]), stddev([]) 错误

空列表最常见于没有匹配到任何值的 filter 的结果,所以即使原始列表有值,对筛选后的列表求 average 也可能失败。

标签

标签就是一个 # 紧跟着一个词,比如 #food。把它写在一行的任何位置,就给这一行打上了标记。标签本身不参与计算,所以这一行仍然显示它自己的答案;同时它把这一行和所有带同一标签的行归为一组。这样 total of #food 就会把这些行加起来:

calc
£12.50 午餐 #food 结果为 £12.50
£8 咖啡 #food 结果为 £8.00
机票 = £420 #trip 结果为 £420.00
total of #food 结果为 £20.50

这正是标签能做而小计做不到的事:这些行不必挨在一起。一周的开销、一次旅行和一张购物清单可以写在同一个块里,各自在底部得出自己的数字。把指针悬停在标签上,即可看到它目前累计了多少。

每一种统计量都可以用在标签上。of 可加可不加,标签写在统计词前面或后面都行;和其他行一样,答案也可以加说明文字或起个名称:

calc
#food £12.50
#food £8
£420 #trip
total of #food 结果为 £20.50
average of #food 结果为 £10.25
count of #food 结果为 2
min of #food 结果为 £8.00
max of #food 结果为 £12.50
#food total 结果为 £20.50
本周餐饮: sum of #food 结果为 £20.50
吃饭均价 = avg #food 结果为 £10.25

sum、total、average、avg、mean、count、min 和 max 都可以这样写。

标签统计量所在的位置和一笔金额一样,所以计算可以从它继续往下写。想从累计额中扣掉定金、把它按比例放大,或者把两个标签放在一起对比,都可以:

calc
£20 采购 #food 结果为 £20.00
£30 下馆子 #food 结果为 £30.00
total of #food - £10 结果为 £40.00
2 * total of #food 结果为 £100.00
厨房用具: total of #food 结果为 £50.00

一行可以带任意多个标签,每个标签都会把这一行算进去。在一个短语里写两个标签,得到的就是同时带这两个标签的行:

calc
£50 晚餐 #trip #food 结果为 £50.00
£30 打车 #trip 结果为 £30.00
£9 三明治 #food 结果为 £9.00
total of #trip 结果为 £80.00
total of #food 结果为 £59.00
total of #trip #food 结果为 £50.00

标签合计涵盖哪些行

标签短语看的行和普通的 total 完全一样,遵循的规则也一样:

  • 它只管自己所在的那一段,往上回溯到上一个合计行、--- 分隔线或 # 标题为止。
  • 它只把同类的量相加。百分比、比率、普通计数以及出错的行都不计入,提示会点名它们,例如“Leaves out line 2 (people = 2)”。
  • 每笔金额只计一次,所以一个带标签的单价如果被后面某个带标签的行乘过,就只算在那一行里,不会两处都算。

所以只要加一个标题,就足以把这周的 #food 和下周的分开:

calc
# 第 1 周
£20 午餐 #food 结果为 £20.00
total of #food 结果为 £20.00
# 第 2 周
£30 午餐 #food 结果为 £30.00
total of #food 结果为 £30.00

没有可以合计的内容时,这一行会直接说明,而不是留空或显示零——出现这种情况,通常是标签拼错了,或者中间有一个你忘了的标题:

calc
£12.50 午餐 #food 结果为 £12.50
total of #drinks 结果为 Unsupported: no lines tagged #drinks above
给水管工打电话 #jobs
total of #jobs 结果为 Unsupported: no amounts tagged #jobs above

标签名的写法

标签名可以包含字母、数字、_、- 和 /,所以 #q1-2026 和 #trip/lisbon 各自都是一个完整的名称。大小写不影响:

calc
£20 机票 #trip/lisbon 结果为 £20.00
£35 酒店 #Trip/Lisbon 结果为 £35.00
total of #trip/lisbon 结果为 £55.00

没有紧跟着一个词的 # 保持原有含义,所以你已经在用的写法都不受影响:

你输入的内容 它是什么
# Weekly shop 注释,因为井号后面有空格
5 + 5 # comment 同样是注释:井号之后的内容都会被忽略
C#4 in Hz 音乐里的升号,因为井号紧跟在音名后面
#1、Invoice #123 编号,不是标签:标签名不能以数字开头
#ff0000、#fff 颜色代码
varlig.app/docs#tags 带片段标识的网址

标签名必须以字母开头;井号后面的三、四、六或八位十六进制数字会被读作颜色,所以 #fee 是颜色,而 #fees 是标签。

笔记里的标签与计算块里的标签

在边栏中整理笔记的那种标签,请参阅标签、链接与反向链接。那种标签到计算块的边界就停下了:写在块里的 #food 只给那一行打标记以便合计,绝不会出现在边栏;而写在块外正文里的 #food 只负责归类笔记,不影响你的计算。想要两种效果都有,就在两处都写上这个标签。另外,这两者有一处细微差别:笔记里的标签用第二个 # 闭合后可以包含空格,而计算块里的标签总是在第一个空格处结束。

列表函数参考

调用 作用
range(start,end) 从 start 到 end 的整数,包含两端
range(start,end,step) 以 step 为步长计数,步长可以是负数或小数,但不能为零
length(list), count(list) 值的个数
sort(list) 从小到大排序;仅限普通数字
reverse(list) 把相同的值按相反顺序排列;适用于任何值
unique(list) 每个值只保留第一次出现的那个
slice(list,start,end) 从索引 start 开始、到索引 end 之前(不含)的值
map(expression,variable,list) 对每个值计算一次表达式
filter(condition,variable,list) 保留使条件为 true 的值
calc
range(1, 5) 结果为 [1, 2, 3, 4, 5]
range(0, 100, 25) 结果为 [0, 25, 50, 75, 100]
range(10, 0, -2) 结果为 [10, 8, 6, 4, 2, 0]
成绩 = [72, 85, 91, 64, 88]
sort(成绩) 结果为 [64, 72, 85, 88, 91]
reverse(sort(成绩)) 结果为 [91, 88, 85, 72, 64]
slice(sort(成绩), 0, 3) 结果为 [64, 72, 85]
unique([4, 2, 4, 6, 2]) 结果为 [4, 2, 6]

reverse(sort(…)) 让最大的值排在最前面,slice(sort(…), 0, 3) 则挑出最低的三个。

切片边界必须满足 0 <= start <= end <= length。start 与 end 相等时得到空列表。没有 成绩[0:2] 这种简写;请写 slice(成绩, 0, 2)。

unique 按值的存储形式精确比较,所以 1 kg 和 1000 g 算作两个不同的值,在小数点后第十位不同的两个结果也不会合并。

map 与 filter

map 对列表中的每个值计算一个表达式。filter 保留通过测试的值。两者都是先写表达式,再写代表每个值的名称,最后写列表:

calc
成绩 = [72, 85, 91, 64, 88]
map(s + 5, s, 成绩) 结果为 [77, 90, 96, 69, 93]
filter(s >= 80, s, 成绩) 结果为 [85, 91, 88]
count(filter(s >= 80, s, 成绩)) 结果为 3
average(filter(s >= 80, s, 成绩)) 结果为 88

filter(s >= 80, s, 成绩) 可以读作“成绩 中满足 s >= 80 的值 s”。两者都适用于单位和金额:

calc
map(p * 1.2, p, [£10, £25, £40]) 结果为 [£12.00, £30.00, £48.00]
支出 = [£42.50, £18.20, £65.00, £23.30]
filter(x > £30, x, 支出) 结果为 [£42.50, £65.00]
sum(filter(x > £30, x, 支出)) 结果为 £107.50

你选的名称只在这次调用内部有效,不会改变笔记中其他地方同名的值:

calc
x = 10
map(x * 2, x, [1, 2, 3]) 结果为 [2, 4, 6]
x 结果为 10

filter 中的条件必须是比较式或其他真/假值。普通数字不会被当作真,所以 filter(x, x, [0, 1, 2]) 会报错。对空列表执行 map 或 filter,得到的仍是空列表。

列表运算

你可以把每个值都乘以或除以同一个数,也可以把两个长度相同的列表逐值相加或相减:

calc
[30, 36, 22] / 40 * 100 结果为 [75, 90, 55]
2 * [3, 1, 4] 结果为 [6, 2, 8]
-[5, -3] 结果为 [-5, 3]
模考 = [62, 70, 60]
期末 = [72, 78, 69]
期末 - 模考 结果为 [10, 8, 9]
average(期末 - 模考) 结果为 9
[1 kg, 2 kg] + [500 g, 500 g] 结果为 [1.5 kg, 2.5 kg]
[72, 85] == [72, 85] 结果为 true

第一行把满分 40 的分数换算成百分比。期末 - 模考 这一行把每位学生的模考分数与期末分数一一对应。

有些运算不支持列表:

  • 给列表加上单个数字,如 成绩 + 5。请改用 map(s + 5, s, 成绩)。
  • 把长度不同的列表相加。值永远不会为了凑齐长度而重复。
  • 用 * 把两个平面列表相乘。要计算逐对乘积之和,请使用 dot:dot([2, 3, 1], [4, 5, 10]) 是 33,比如两杯单价 4 的咖啡、三杯单价 5 的茶和一块单价 10 的蛋糕。对于由行组成的列表,* 表示矩阵乘法,请参阅向量与矩阵。

由行组成的列表

由行组成的列表就像一张小表格。average 和 sum 按列计算,map 则可以逐行计算:

calc
# 每行是一名学生:[模考, 期末]
成绩单 = [[62, 72], [70, 78], [60, 69]]
average(成绩单) 结果为 [64, 73]
sum(成绩单) 结果为 [192, 219]
map(average(r), r, 成绩单) 结果为 [67, 74, 64.5]

median、min、max 和 stddev 不接受由行组成的列表。请像最后一行那样用 map 逐行处理,或者把某一列单独提取成一个列表。

所有这些运算的确切规则,请参阅高等数学:功能与限制参考页。

综合运用

下面是手表记录的一周步数,以及每日目标:

calc
# 步数,周一至周日
步数 = [8200, 10400, 6300, 12000, 9100, 7400, 9600]
目标 = 9000
sum(步数) 结果为 63,000
average(步数) 结果为 9,000
median(步数) 结果为 9,100
达标天数: count(filter(s >= 目标, s, 步数)) 结果为 4
极差: max(步数) - min(步数) 结果为 5,700
# 每步约 0.75 m
步行距离 = sum(步数) * 0.75 m
步行距离 in km 结果为 47.25 km

平均值恰好等于目标,但只有四天达标,而且最好和最差的两天相差 5,700 步。修改 目标,或者粘贴下一周的步数,每一行都会随之更新。