Skip to content
Varlig Guide
Varlig home

Lists and statistics

A list keeps several values together under one name, such as a week of step counts, a set of exam marks or a month of receipts. Once the values are in a list, you can total them, average them, measure how spread out they are, and pick out the ones that matter.

This page covers writing and indexing lists, summary statistics, sorting and slicing, transforming a list with map and filter, and arithmetic on whole lists. Reach for it whenever you have a column of figures to summarise. Lists of rows can also act as matrices, which have their own page.

Writing a list

Put the values in square brackets, separated by commas:

calc
scores = [72, 85, 91, 64, 88] gives [72, 85, 91, 64, 88]
scores[0] gives 72
scores[4] gives 88
length(scores) gives 5

A value’s position in the list is its index, written in square brackets after the list. Indexes start at zero, so scores[0] is the first mark and scores[4] is the fifth. The last element is always at length(scores) - 1. A negative, fractional or too-large index is an error; indexes don’t wrap around from the end.

Elements can be calculations, quantities with units, or other lists:

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

With nested lists, the first index picks the inner list and the second picks a value from it: [1] selects [3, 4], then [0] selects 3.

Thousands separators work inside a list, so you can paste figures as they’re written. Put a space after each comma between values, and a comma followed by three digits stays part of the number:

calc
salaries = [£32,000, £41,500, £38,250] gives [£32,000.00, £41,500.00, £38,250.00]
average(salaries) gives £37,250.00

A few things to watch for:

  • Without spaces, every comma separates, so [8200,10400] has two values. A list such as [100,200,300] could be one number or three, so Varlig shows an error that spells out both.
  • Answers show thousands separators and a space after each comma, so [8,200, 10,400] is a list of two values.
  • A list holds at most 1,024 values.

Summary statistics

calc
scores = [72, 85, 91, 64, 88]
sum(scores) gives 400
average(scores) gives 80
median(scores) gives 85
min(scores) gives 64
max(scores) gives 91
count(scores) gives 5

mean and avg are other names for average, total for sum, stdev for stddev and count for length, so spreadsheet habits carry over. product multiplies the values together. There’s no percentile function; median gives the middle value.

With a named list, you can also write the statistic in words:

calc
scores = [72, 85, 91, 64, 88]
average of scores gives 80
total of scores gives 400

sum of, mean of, median of, min of, max of and count of work the same way. After of, write a name or the values themselves, separated by commas, with or without round brackets. For values in square brackets, use the function form, as in average([72, 85, 91]).

Most statistics, including sum, product, average, median, min, max, count and stddev, also accept separate values instead of a list:

calc
max(72, 85, 91) gives 91
average of 70, 85, 91 gives 82
mean of (1,2,3) gives 2
average(1,200, 1,800) gives 1,500

Adding up the lines above

A line that says only sum or total adds up the answers above it, back to the previous sum or total line or a --- divider. It works like the Subtotal option in a line’s context menu, so each section of a note gets its own total as you type:

calc
# Groceries
bread = £1.20
milk = £1.45
eggs = £2.30
total gives £4.95
# Household
bin bags = £3.50
washing up liquid = £1.80
total gives £5.30

If you’ve given a value the name sum or total, the line shows your value instead.

Spread: variance and standard deviation

calc
scores = [72, 85, 91, 64, 88]
variance(scores) gives 132.5
stddev(scores) to 1 dp gives 11.5

Both are sample statistics: they divide by one less than the number of values (n - 1), which is the usual choice when your figures are a sample from something larger. They need at least two values. Add to 1 dp after any statistic to round it.

If your list is the whole population, you want to divide by n instead. Build it from map, described below:

calc
# Train delays in minutes
delays = [2, 4, 4, 4, 5, 5, 7, 9]
stddev(delays) gives 2.1380899353
centre = average(delays) gives 5
sqrt(sum(map((x - centre)^2, x, delays)) / count(delays)) gives 2

Lists with units

sum, average, median, min, max and stddev keep units, and convert between compatible ones:

calc
commutes = [24 min, 31 min, 27 min, 22 min]
sum(commutes) gives 104 min
average(commutes) gives 26 min
median(commutes) gives 25.5 min
sum([1 kg, 500 g]) gives 1.5 kg

variance only accepts plain numbers, because its answer would be in squared units. sort also only works on plain numbers. A statistic on values with incompatible units, such as sum([1 kg, 3 m]), gives an error rather than quietly skipping values.

Empty lists

Call on an empty list Result
sum([]) 0
product([]) 1
count([]), length([]) 0
average([]), median([]), min([]), max([]) Error
variance([]), stddev([]) Error

An empty list most often turns up as the result of a filter that matched nothing, so an average of a filtered list can fail even when the original list has values.

List reference

Call What it does
range(start,end) Whole numbers from start to end, including both ends
range(start,end,step) Count by step, which can be negative or fractional but not zero
length(list), count(list) Number of values
sort(list) Smallest to largest; plain numbers only
reverse(list) The same values in reverse order; any values
unique(list) Keep the first occurrence of each value
slice(list,start,end) Values from index start up to, but not including, index end
map(expression,variable,list) Work out the expression once for each value
filter(condition,variable,list) Keep the values for which the condition is true
calc
range(1, 5) gives [1, 2, 3, 4, 5]
range(0, 100, 25) gives [0, 25, 50, 75, 100]
range(10, 0, -2) gives [10, 8, 6, 4, 2, 0]
scores = [72, 85, 91, 64, 88]
sort(scores) gives [64, 72, 85, 88, 91]
reverse(sort(scores)) gives [91, 88, 85, 72, 64]
slice(sort(scores), 0, 3) gives [64, 72, 85]
unique([4, 2, 4, 6, 2]) gives [4, 2, 6]

reverse(sort(…)) gives largest first, and slice(sort(…), 0, 3) picks out the three lowest.

Slice bounds must satisfy 0 <= start <= end <= length. Equal start and end give an empty list. There is no scores[0:2] shorthand; write slice(scores, 0, 2).

unique compares values exactly as they are stored, so 1 kg and 1000 g count as two different values, and two results that differ in the tenth decimal place aren’t merged.

Map and filter

map works out an expression for each value in a list. filter keeps the values that pass a test. In both, the expression comes first, then a name to stand for each value, then the list:

calc
scores = [72, 85, 91, 64, 88]
map(s + 5, s, scores) gives [77, 90, 96, 69, 93]
filter(s >= 80, s, scores) gives [85, 91, 88]
count(filter(s >= 80, s, scores)) gives 3
average(filter(s >= 80, s, scores)) gives 88

Read filter(s >= 80, s, scores) as “the values s in scores where s >= 80”. Both work with units and money:

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

The name you choose only exists inside the call. It doesn’t change a value of the same name elsewhere in the note:

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

The condition in filter must be a comparison or another true/false value. A plain number isn’t treated as true, so filter(x, x, [0, 1, 2]) is an error. Mapping or filtering an empty list gives an empty list.

List arithmetic

You can multiply or divide every value by a single number, and add or subtract two lists of the same length value by value:

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

The first line turns marks out of 40 into percentages. The finals - mocks line pairs each student’s mock mark with their final mark.

Some operations aren’t supported on lists:

  • Adding a single number to a list, as in scores + 5. Use map(s + 5, s, scores) instead.
  • Adding lists of different lengths. Values are never repeated to make lengths match.
  • Multiplying two flat lists with *. For the sum of pairwise products, use dot: dot([2, 3, 1], [4, 5, 10]) is 33, for example two coffees at 4, three teas at 5 and one cake at 10. Between lists of rows, * is matrix multiplication, covered in Vectors and matrices.

Lists of rows

A list of rows works like a small table. average and sum work down the columns, and map can work across the rows:

calc
# Each row is one student: [mock, final]
results = [[62, 72], [70, 78], [60, 69]]
average(results) gives [64, 73]
sum(results) gives [192, 219]
map(average(r), r, results) gives [67, 74, 64.5]

median, min, max and stddev don’t accept lists of rows. Use map over the rows, as in the last line, or pull out a column into its own list.

The exact rules for all of these operations are in the advanced mathematics reference.

Putting it together

Here is a week of step counts from a watch, with a daily goal:

calc
# Steps, Monday to Sunday
steps = [8200, 10400, 6300, 12000, 9100, 7400, 9600]
goal = 9000
sum(steps) gives 63,000
average(steps) gives 9,000
median(steps) gives 9,100
Days on target: count(filter(s >= goal, s, steps)) gives 4
Spread: max(steps) - min(steps) gives 5,700
# Roughly 0.75 m per step
walked = sum(steps) * 0.75 m
walked in km gives 47.25 km

The average lands exactly on the goal, but only four days reached it, and there are 5,700 steps between the best and worst days. Change goal or paste in next week’s counts and every line updates.