列表与统计
列表把多个值集中放在一个名称下,比如一周的步数、一组考试分数或一个月的收据。把值放进列表后,你就可以求和、求平均值、衡量它们的离散程度,并挑出重要的值。
本页介绍如何书写列表和按索引取值、汇总统计、合计上方的行、用标签给行打上标记以便把分散各处的行加总、排序与切片、用 map 和 filter 变换列表,以及对整个列表进行运算。每当你有一列数字需要汇总时,都可以参考本页。由行组成的列表还可以当作矩阵使用,矩阵有专门的页面介绍。
书写列表
把值放在方括号里,用逗号分隔:
成绩 = [72, 85, 91, 64, 88] 结果为 [72, 85, 91, 64, 88]成绩[0] 结果为 72成绩[4] 结果为 88length(成绩) 结果为 5值在列表中的位置称为索引,写在列表后面的方括号里。索引从零开始,所以 成绩[0] 是第一个分数,成绩[4] 是第五个。最后一个元素总是位于 length(成绩) - 1。负数、小数或超出范围的索引都会报错;索引不会从末尾倒着绕回来。
元素可以是计算式、带单位的数量,也可以是其他列表:
[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。
千位分隔符在列表中同样有效,所以你可以按数字原本的写法直接粘贴。在值与值之间的每个逗号后面加一个空格;逗号后面紧跟三位数字时,仍然算作同一个数字的一部分:
工资 = [£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 个值。
汇总统计
成绩 = [72, 85, 91, 64, 88]sum(成绩) 结果为 400average(成绩) 结果为 80median(成绩) 结果为 85min(成绩) 结果为 64max(成绩) 结果为 91count(成绩) 结果为 5mean 和 avg 是 average 的别名,total 是 sum 的别名,stdev 是 stddev 的别名,count 是 length 的别名,所以电子表格里的习惯写法可以照搬过来。product 把所有值相乘。关于出现最多的值、百分位数和四分位数,请参阅下文。
对于命名的列表,你也可以用文字写出统计量:
成绩 = [72, 85, 91, 64, 88]average of 成绩 结果为 80total of 成绩 结果为 400sum of、mean of、median of、min of、max of 和 count of 的用法相同。在 of 后面写一个名称,或者直接写出用逗号分隔的值,加不加圆括号都可以。如果值写在方括号里,请使用函数形式,如 average([72, 85, 91])。
大多数统计函数,包括 sum、product、average、median、min、max、count 和 stddev,也接受分开书写的值,而不一定是列表:
max(72, 85, 91) 结果为 91sum(1, 2, 3, 4) 结果为 10average of 70, 85, 91 结果为 82mean of (1,2,3) 结果为 2average(1,200, 1,800) 结果为 1,500合计上方的行
只写了 sum、total、subtotal、grand total、average、max 或 min 的一行,会对它上方的答案求出相应的数字。它只管自己所在的那一段,这一段从上一个合计行、--- 分隔线或 # 标题开始,所以笔记中的每个部分都能在你输入时得到各自的数字。它的作用与某一行快捷菜单中的 小计(小计)选项相同:
# 食品杂货面包 = £1.20牛奶 = £1.45鸡蛋 = £2.30total 结果为 £4.95# 日用品垃圾袋 = £3.50洗洁精 = £1.80total 结果为 £5.30这个词前面可以加说明文字,也可以给它起个名称、把结果换算成别的单位,或者在后面写注释,这样整行读起来就和笔记的其余部分一样自然:
门票 = £64火车 = £41.20预计合计: total 结果为 £105.20est = total 会把这个数字存进一个名称,total // 还没订 则在旁边加一条注释。total in kg 会先换算再显示,这一段里克和千克混着写时特别有用。统计词写在运算符旁边时,表示它单独成行时会显示的那个数字,所以 £5 + subtotal 就是在当前小计上再加五英镑。
# 包裹12 kg 结果为 12 kg4 kg 结果为 4 kg850 g 结果为 850 gtotal in kg 结果为 16.85 kgmax 结果为 12 kg如果你给某个值起名为 sum 或 total,这一行会显示你的值。如果上方没有可以合计的内容,这一行会显示 Unsupported: no amounts above to add up,而不是留空或显示零——出现这种情况,通常是因为中间有一个你忘了的标题。
每笔金额只计一次。如果这一段里后面的某一行是根据某个命名金额算出来的,合计只算那一行,而不会两笔都算,所以一张写着单价和数量的购物清单加出来的正是你实际要付的钱:
衬衫 = £18.50短裤 = £99 * 衬衫 结果为 £166.5010 * 短裤 结果为 £90.00手续费 = £40增值税 = 手续费 * 20% 结果为 £8.00total 结果为 £304.50衬衫 和 短裤 已经计入了用到它们的那两行,而 手续费 仍然留在合计里,因为 增值税 只取了它的一部分。
这条规则会沿着名称一路追溯下去。如果笔记把一笔钱拆成几份、再把这几份加回去,那么加总的那一行会计入,被拆分的那笔金额也会计入:
奖金池 = £900一等 = 50% of 奖金池 结果为 £450.00二等 = 30% of 奖金池 结果为 £270.00三等 = 20% of 奖金池 结果为 £180.00一等 + 二等 + 三等 结果为 £900.00total 结果为 £900.00只有同类的量才会相加。上方有金额或带单位的量时,百分比、比率和普通计数都不会计入,出错的行也一样。粘贴成一列的普通数字,只要像金额那样精确到分位就会计入;小数位更多的(比如汇率或系数)则不会。合计行的提示会点名它略过的每一项,例如“Leaves out line 3 (people = 2)”或“Leaves out line 2 (an error)”,让你一眼看清这个数字包含了什么。
如果紧挨着合计行的上方,有两笔及以上不带名称的金额,而它们上面又有一行是根据名称算出来的,那么只把这几笔不带名称的加起来。这样一来,笔记开头算出的预算就不会在下面的清单里被重复计算:
预算 = £18,000剩余 = 预算 - £6,388.25 结果为 £11,611.75- 垃圾清运 £250 结果为 £250.00- 深度保洁 £120 结果为 £120.00subtotal 结果为 £370.00要把并不相邻的行加总,请改用标签给它们打上标记。
最常出现的值
mode 给出出现次数比其他任何值都多的那个值,modes 则以列表形式给出并列出现最多的所有值:
分数 = [3, 4, 4, 5, 5, 5, 6]mode(分数) 结果为 5modes([1, 1, 2, 2, 3]) 结果为 [1, 2]只有当某一个值严格地出现得最多时,mode 才会给出答案。如果没有任何值重复出现,或者几个值并列,它会如实说明,而不会随便挑一个:
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):
成绩 = [72, 85, 91, 64, 88]percentile(成绩, 50) 结果为 85percentile(成绩, 25) 结果为 72quartile(成绩, 3) 结果为 88quartile(成绩, 4) 结果为 91percentile([1, 2, 3, 4], 25) 结果为 1.75quartile([1, 2, 3, 4], 3) 结果为 3.25第 50 百分位数就是中位数,第 0 和第 100 百分位数 —— 也就是 quartile(list, 0) 和 quartile(list, 4) —— 是最小值和最大值,与 min 和 max 相同。名次超出范围会报错,而不会退回到最接近的那个合法值:
percentile([1, 2, 3, 4], 101) 结果为 Unsupported: A percentile is between 0 and 100quartile([1, 2, 3, 4], 5) 结果为 Unsupported: A quartile is 0, 1, 2, 3 or 4离散程度:方差与标准差
成绩 = [72, 85, 91, 64, 88]variance(成绩) 结果为 132.5stddev(成绩) to 1 dp 结果为 11.5两者都是样本统计量:它们除以值的个数减一(n - 1),当你的数据是从更大整体中抽取的样本时,通常这样计算。它们至少需要两个值。在任何统计量后面加上 to 1 dp 即可舍入。
当你的列表是整个总体、而不是一份样本时,请使用总体形式:它们除以 n,只需要一个值:
# 列车延误分钟数延误 = [2, 4, 4, 4, 5, 5, 7, 9]sample_variance(延误) 结果为 4.5714285714population_variance(延误) 结果为 4sample_stddev(延误) 结果为 2.1380899353population_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 会保留单位,并在兼容的单位之间换算。这些值按第一个值的单位来读取,答案也以该单位给出:
通勤 = [24 min, 31 min, 27 min, 22 min]sum(通勤) 结果为 1 hour 44 minaverage(通勤) 结果为 26 minmedian(通勤) 结果为 25.5 minpercentile(通勤, 25) 结果为 23.5 minpopulation_stddev(通勤) 结果为 3.3911649916 minsum([1 kg, 500 g]) 结果为 1.5 kgmodes([1 kg, 500 g, 1 kg, 500 g]) 结果为 [0.5 kg, 1 kg]方差是个例外:它要对观测值求平方,没有哪个单位能挺过这一步,所以它们只接受普通数字。
sample_variance([1 kg, 2 kg]) 结果为 Unsupported: A variance squares its observations, so it takes plain numbers; use stddev for amounts with a unitsort 同样只适用于普通数字。对单位不兼容的值(如 sum([1 kg, 3 m]))进行统计会报错,而不会悄悄跳过某些值。
所有这些背后的精确性规则,请参阅引擎作出的保证。
空列表
| 对空列表调用 | 结果 |
|---|---|
sum([]) |
0 |
product([]) |
1 |
count([]), length([]) |
0 |
average([]), median([]), min([]), max([]) |
错误 |
variance([]), stddev([]) |
错误 |
空列表最常见于没有匹配到任何值的 filter 的结果,所以即使原始列表有值,对筛选后的列表求 average 也可能失败。
标签
标签就是一个 # 紧跟着一个词,比如 #food。把它写在一行的任何位置,就给这一行打上了标记。标签本身不参与计算,所以这一行仍然显示它自己的答案;同时它把这一行和所有带同一标签的行归为一组。这样 total of #food 就会把这些行加起来:
£12.50 午餐 #food 结果为 £12.50£8 咖啡 #food 结果为 £8.00机票 = £420 #trip 结果为 £420.00total of #food 结果为 £20.50这正是标签能做而小计做不到的事:这些行不必挨在一起。一周的开销、一次旅行和一张购物清单可以写在同一个块里,各自在底部得出自己的数字。把指针悬停在标签上,即可看到它目前累计了多少。
每一种统计量都可以用在标签上。of 可加可不加,标签写在统计词前面或后面都行;和其他行一样,答案也可以加说明文字或起个名称:
#food £12.50#food £8£420 #triptotal of #food 结果为 £20.50average of #food 结果为 £10.25count of #food 结果为 2min of #food 结果为 £8.00max of #food 结果为 £12.50#food total 结果为 £20.50本周餐饮: sum of #food 结果为 £20.50吃饭均价 = avg #food 结果为 £10.25sum、total、average、avg、mean、count、min 和 max 都可以这样写。
标签统计量所在的位置和一笔金额一样,所以计算可以从它继续往下写。想从累计额中扣掉定金、把它按比例放大,或者把两个标签放在一起对比,都可以:
£20 采购 #food 结果为 £20.00£30 下馆子 #food 结果为 £30.00total of #food - £10 结果为 £40.002 * total of #food 结果为 £100.00厨房用具: total of #food 结果为 £50.00一行可以带任意多个标签,每个标签都会把这一行算进去。在一个短语里写两个标签,得到的就是同时带这两个标签的行:
£50 晚餐 #trip #food 结果为 £50.00£30 打车 #trip 结果为 £30.00£9 三明治 #food 结果为 £9.00total of #trip 结果为 £80.00total of #food 结果为 £59.00total of #trip #food 结果为 £50.00标签合计涵盖哪些行
标签短语看的行和普通的 total 完全一样,遵循的规则也一样:
- 它只管自己所在的那一段,往上回溯到上一个合计行、
---分隔线或#标题为止。 - 它只把同类的量相加。百分比、比率、普通计数以及出错的行都不计入,提示会点名它们,例如“Leaves out line 2 (people = 2)”。
- 每笔金额只计一次,所以一个带标签的单价如果被后面某个带标签的行乘过,就只算在那一行里,不会两处都算。
所以只要加一个标题,就足以把这周的 #food 和下周的分开:
# 第 1 周£20 午餐 #food 结果为 £20.00total of #food 结果为 £20.00# 第 2 周£30 午餐 #food 结果为 £30.00total of #food 结果为 £30.00没有可以合计的内容时,这一行会直接说明,而不是留空或显示零——出现这种情况,通常是标签拼错了,或者中间有一个你忘了的标题:
£12.50 午餐 #food 结果为 £12.50total of #drinks 结果为 Unsupported: no lines tagged #drinks above给水管工打电话 #jobstotal of #jobs 结果为 Unsupported: no amounts tagged #jobs above标签名的写法
标签名可以包含字母、数字、_、- 和 /,所以 #q1-2026 和 #trip/lisbon 各自都是一个完整的名称。大小写不影响:
£20 机票 #trip/lisbon 结果为 £20.00£35 酒店 #Trip/Lisbon 结果为 £35.00total 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 的值 |
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 保留通过测试的值。两者都是先写表达式,再写代表每个值的名称,最后写列表:
成绩 = [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, 成绩)) 结果为 3average(filter(s >= 80, s, 成绩)) 结果为 88filter(s >= 80, s, 成绩) 可以读作“成绩 中满足 s >= 80 的值 s”。两者都适用于单位和金额:
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你选的名称只在这次调用内部有效,不会改变笔记中其他地方同名的值:
x = 10map(x * 2, x, [1, 2, 3]) 结果为 [2, 4, 6]x 结果为 10filter 中的条件必须是比较式或其他真/假值。普通数字不会被当作真,所以 filter(x, x, [0, 1, 2]) 会报错。对空列表执行 map 或 filter,得到的仍是空列表。
列表运算
你可以把每个值都乘以或除以同一个数,也可以把两个长度相同的列表逐值相加或相减:
[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 则可以逐行计算:
# 每行是一名学生:[模考, 期末]成绩单 = [[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 逐行处理,或者把某一列单独提取成一个列表。
所有这些运算的确切规则,请参阅高等数学:功能与限制参考页。
综合运用
下面是手表记录的一周步数,以及每日目标:
# 步数,周一至周日步数 = [8200, 10400, 6300, 12000, 9100, 7400, 9600]目标 = 9000sum(步数) 结果为 63,000average(步数) 结果为 9,000median(步数) 结果为 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 步。修改 目标,或者粘贴下一周的步数,每一行都会随之更新。