<aside>
<img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a5a1e3ce-00fa-46e4-9a75-58c2aed9e8ce/Notion_Fundamentals_with_Thomas_Frank_-_Avatar_2021.png" alt="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a5a1e3ce-00fa-46e4-9a75-58c2aed9e8ce/Notion_Fundamentals_with_Thomas_Frank_-_Avatar_2021.png" width="40px" /> Notion formulas current can loop over Lists with the map()
and filter()
functions, but these will always use the length of the list you’re passing into them. What if you need to define a custom number of iterations for the loop? To do this, you can use the repeat()
function to create a string of length n, then use the split()
function to get a List of length n.
Created by Thomas Frank | Learn Notion Formulas | Notion Basics | Templates | Twitter
</aside>
"."
.repeat(10)
.split(".")
.map(
index * 2
)
This is about the simplest demonstration of this trick. A .
character is repeated 10 times to create the string “……….”, which is then split on the same character to create a List of length 10
. Finally, we map through the list, multiplying each item’s index by 2.
This formula was inspired by Ben Borowski’s work: https://twitter.com/typeoneerror/status/1707777343820062996 (however, his formula does exhibit the off-by-one error I describe below. He’s posted an update here: Business days between a range)
lets(
startDate, prop("Date").dateStart(),
endDate, prop("Date").dateEnd(),
numberOfDays, dateBetween(endDate, startDate, "days"),
","
.repeat(numberOfDays == 0 ? numberOfDays + 1 : numberOfDays)
.split(numberOfDays == 0 ? "." : ",")
.filter([1,3,5].includes(startDate.dateAdd(index, "days").day()))
.length()
)
If our workout schedule is Monday, Wednesday, and Friday, how many workouts are between two dates?
This can also be used to find the number of business days between two dates. It’s useful because Notion currently doesn’t provide a built-in way to get a List where each element is one of the individual dates between a start and end date.
Careful! It’s easy to introduce an off-by-one error into your formula if you don’t fully understand what this trick does.
"There are only two hard problems in Computer Science: cache invalidation, naming things, and off-by-one errors." – Phil Karlton (sort of)
Note the lines .repeat(numberOfDays == 0 ? numberOfDays + 1 : numberOfDays)
and .split(numberOfDays == 0 ? "." : ",")
– these both must be present to allow the repeat().split()
function chain to be able to output a length of 1
. This length is needed in the Workout Days example in order to accurately check dates that don’t contain a range (or a range that begins and ends on the same day).
So what’s going on?
In this example, we’re getting the number of days between the start and end date. But if we want to check all dates, we need to add one. E.g. dateBetween(prop("Date").dateEnd(), prop("Date").dateStart(), "days")
for August 12 → August 13 will return 1
. That makes sense - there’s a single 24-hour period between these two dates. But we want to check both dates here.
As it turns out, the repeat().split()
trick is already adding 1
for us.
Now, this “for loop” trick relies on making a string consisting of a single character repeated n times with repeat()
, then splitting the string using that very character as the separator using split()
.
E.g. ",".repeat(10).split(",")
will give you a List containing 11 items, all of which are empty
.
Your resulting List will have a resulting length of n + 1.