How can I instantiate a dictionary with a variable key name?

I feel like I’m missing something obvious, but for all my looking and attempts I haven’t been able to find the answer.

I am loading data from a text file and after some processing adding it to a dictionary. I want a dictionary where the keys are user names and the values are dictionaries describing the user. On the docs page for dictionaries it shows how to create a dictionary with key value pairs:

#let dict = (
  name: "Typst",
  born: 2019,
)

But because the keys I will be using are variables I can’t type them in like this.

Here are the methods I’ve tried. Only the fourth version achieves what I want, however, I cant help but think there is a more elegant way of doing it.

#let userName = "joe"
#let userData = (birthday: 1, phone: 123)

//Doesn't work - key is the name of the userName variable, not its value
#let dict1 = (userName: userData)
#dict1
//(userName: (birthday: 1, phone: 123))

//Error at 'userName'
#let dict2 = dictionary(userName, userData)
#dict2
//expected module, found string

//Error at 'userName'
#let dict3 = ()
#dict3.insert(userName, userData)
#dict3
//expected integer, found string

//Works
#let dict4 = (x: none)
#dict4.insert(userName, userData)
//Only remove if the value remains unchanged - shouldn't remove a user with "x" as a name
#if dict4.at("x") == none { dict4.remove("x") }
#dict4
//(joe: (birthday: 1, phone: 123))

To give a bit more context, l am creating a variable that is set to none, then when I get my first user data I set that variable to a new dictionary. Any further users are simply added to the existing dictionary with .insert(keyName, value).

While editing my initial post I found another way which provides the correct result. It still doesn’t answer the question of how to create a dictionary with a variable key name, however.

#let userName = "joe"
#let userData = (birthday: 1, phone: 123)

//Works
#let dict5 = (:)
#dict5.insert(userName, userData)
#dict5
//(joe: (birthday: 1, phone: 123))

You’re looking for this syntax:

#let userName = "joe"
#let userData = (birthday: 1, phone: 123)

#let dict1 = ((userName): userData)
#dict1

This is not really special syntax, it’s just a parenthesized expression. As you’ve seen, a bare identifier will be directly used as the key – but any other expression will be evaluated to get the key. By putting the identifier in parentheses, you make sure that a variable access is performed.

3 Likes

Thanks, that’s what I was missing. So this uses a similar syntax when you have a function defined as the value of a dictionary:

#let funcs = ("add1": x => x + 1)
#funcs.add1(0) //Doesn't work
#(funcs.add1)(0) //Works

Thanks for the help!

1 Like