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:
scores = [72, 85, 91, 64, 88] gives [72, 85, 91, 64, 88]scores[0] gives 72scores[4] gives 88length(scores) gives 5A 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:
[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 3With 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:
salaries = [£32,000, £41,500, £38,250] gives [£32,000.00, £41,500.00, £38,250.00]average(salaries) gives £37,250.00A 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
scores = [72, 85, 91, 64, 88]sum(scores) gives 400average(scores) gives 80median(scores) gives 85min(scores) gives 64max(scores) gives 91count(scores) gives 5mean 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:
scores = [72, 85, 91, 64, 88]average of scores gives 80total of scores gives 400sum 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:
max(72, 85, 91) gives 91average of 70, 85, 91 gives 82mean of (1,2,3) gives 2average(1,200, 1,800) gives 1,500Adding 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:
# Groceriesbread = £1.20milk = £1.45eggs = £2.30total gives £4.95# Householdbin bags = £3.50washing up liquid = £1.80total gives £5.30If you’ve given a value the name sum or total, the line shows your value instead.
Spread: variance and standard deviation
scores = [72, 85, 91, 64, 88]variance(scores) gives 132.5stddev(scores) to 1 dp gives 11.5Both 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:
# Train delays in minutesdelays = [2, 4, 4, 4, 5, 5, 7, 9]stddev(delays) gives 2.1380899353centre = average(delays) gives 5sqrt(sum(map((x - centre)^2, x, delays)) / count(delays)) gives 2Lists with units
sum, average, median, min, max and stddev keep units, and convert between compatible
ones:
commutes = [24 min, 31 min, 27 min, 22 min]sum(commutes) gives 104 minaverage(commutes) gives 26 minmedian(commutes) gives 25.5 minsum([1 kg, 500 g]) gives 1.5 kgvariance 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 |
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:
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 3average(filter(s >= 80, s, scores)) gives 88Read filter(s >= 80, s, scores) as “the values s in scores where s >= 80”. Both work with
units and money:
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.50The name you choose only exists inside the call. It doesn’t change a value of the same name elsewhere in the note:
x = 10map(x * 2, x, [1, 2, 3]) gives [2, 4, 6]x gives 10The 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:
[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 trueThe 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. Usemap(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, usedot:dot([2, 3, 1], [4, 5, 10])is33, 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:
# 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:
# Steps, Monday to Sundaysteps = [8200, 10400, 6300, 12000, 9100, 7400, 9600]goal = 9000sum(steps) gives 63,000average(steps) gives 9,000median(steps) gives 9,100Days on target: count(filter(s >= goal, s, steps)) gives 4Spread: max(steps) - min(steps) gives 5,700# Roughly 0.75 m per stepwalked = sum(steps) * 0.75 mwalked in km gives 47.25 kmThe 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.