Tables as maps
Using a table as a set of named fields, reading and writing keys, walking the pairs, and printing them in a stable order.
Keys and values
The same table can hold values under names instead of numbers. local ages = {Ada = 36, Grace = 45} stores two values under the keys Ada and Grace.
You read a value with a dot: the age of Ada, written as a name and a dot and a field. That dot form is a short way of writing the same lookup with the key in square brackets.
Any value can be a key
A key can be a string, a number, or even a table. Keys that are not valid names use square brackets, which is how you store a value under a number.
Asking for a key that is not there gives nil, and that is exactly how you test whether a field exists: a missing name comes back empty rather than raising an error.
Walking a map
pairs walks every key and value in the table. The order is not promised, so do not depend on it. When the output must be stable, collect the keys, sort them, and walk that list instead.
This is the single most common source of surprising output in Lua. The fix is always the same: sort the keys before you print them.
Keys are identities
A table stores each value under a key, and it compares keys by identity. Two strings with the same characters are the same key, and the numbers 1 and 1.0 are the same key too. Two tables with the same fields are not: each table is its own identity, so each is a different key.
Assigning nil to a key removes it. That is the one assignment that changes the shape of the table rather than the value in it, and it is why t[k] = nil and t[k] = false mean different things.
Reading a map, and walking it
t.name is sugar for t["name"]; the dot only works when the key looks like a name. Reading a key that was never set gives nil, and a truth test therefore cannot tell a missing key from a key whose value is false.
pairs hands you every key and value, but in no promised order. If the output has to be stable, collect the keys, sort them, and then look each value up. The table itself keeps no order for you to rely on.
One table, two halves
A Lua table is both a list and a map at once. Values under 1, 2, 3 form the array part, and values under names or arbitrary keys form the hash part. The same table can hold both: {10, 20, name = "Ada"} has two numbered slots and one named field.
The length sign only knows the array part, and pairs visits both. That is why a mixed table is legal but awkward: #t counts the numbered run, while a loop over pairs also prints the named field. Keep the two roles in separate tables unless the shape really is a record with a list inside it.
A map as a tally
The counting idiom is counts[word] = (counts[word] or 0) + 1. The lookup gives nil the first time, or turns that into zero, and the assignment stores one. On later passes the stored number is used, so the count rises. The brackets matter: the addition has to finish before the assignment writes back.
Reading a missing key never raises, which is what makes the idiom short. It also means a typo in a key silently starts a new entry instead of failing. When a missing key is a bug rather than a first visit, check with ~= nil or keep the set of allowed keys beside the table.
A small directory
local ages = {Ada = 36, Grace = 45, Alan = 41}
print(ages.Ada)
ages.Linus = 54
print(ages.Linus)
-- Sort the keys so the output is always the same.
local names = {}
for name in pairs(ages) do
names[#names + 1] = name
end
table.sort(names)
for _, name in ipairs(names) do
print(name .. " is " .. ages[name])
endThree map mistakes. Using # to count a map: the length sign only knows about the list part, so a table of named fields reports zero. Writing if t[k] then when false is a legal value, because that test also rejects a key that is present. And printing straight from pairs when the order matters, which gives different output on different runs.
Try these next
- Count how often each word appears in a sentence, then print the counts in alphabetical order.
- Store a value under a numeric key with square brackets, and read it back with the same number.
- Set a key to false, then test for it with
~= nilinstead of a plain truth test.
Ages, in a steady order
Run it and see the names come out sorted, not in the order they were written. Then add two people of your own and print the oldest name by comparing the values as you walk.
Counting words in a sentence
Run it and check the counts against the sentence. Then change the sentence, and add one more mention of a word so you can watch its count rise.
pairs visits keys in an order the language does not guarantee. A program that prints in whatever order the table happens to give is a program that will print something different tomorrow, so sort the keys when the order matters.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
What does a name and a dot and a field mean on a table?
