Lists and tables
A table keeps many values together. It is the only way Luawe has to do that, and it does two jobs: a list of values in order, and a set of values by name.
Lists
local colours = { "red", "green", "blue" }
print(colours[1]) -- places are counted from 1
print(#colours) -- # is how many there are
colours[2] = "yellow"
colours[#colours + 1] = "pink" -- a new one at the end
print(table.concat(colours, ", "))It prints
red
3
red, yellow, blue, pinkAsking for a place that has nothing in it gives nil; it is not an error.
The table library does the everyday work:
local queue = { "b", "c" }
table.insert(queue, "d") -- at the end
table.insert(queue, 1, "a") -- at place 1: the others move up
print(table.concat(queue, " "))
local last = table.remove(queue) -- takes the last one out
local first = table.remove(queue, 1) -- takes the first: the others move down
print(first, last, #queue)
print(table.find(queue, "c")) -- where is it?It prints
a b c d
a d 2
2table.sort puts a list in order, numbers by size and strings by the alphabet. With a function it sorts any way you like: the function gets two values and says whether the first belongs before the second.
local names = { "saw", "block", "spike" }
table.sort(names)
print(table.concat(names, " "))
table.sort(names, function(a, b)
return #a < #b -- the shortest first
end)
print(table.concat(names, " "))It prints
block saw spike
saw block spikeValues by name
A table can keep values under names, called keys:
local door = { name = "gate", open = false, width = 3 }
print(door.name)
door.open = true -- change one
door.colour = "blue" -- add one
door.width = nil -- take one away
for key, value in door do
print(key, value)
endIt prints
gate
name gate
open true
colour bluedoor.name is short for door["name"]. The long form is needed when the key is not a plain word, or is in a variable:
local stock = { ["red key"] = 1, gems = 12 }
local wanted = "gems"
print(stock["red key"], stock[wanted])It prints
1 12Any value except nil can be a key: numbers, strings, even things of the level.
local hits = {}
for _, thing in things.all("target") do
hits[thing] = 0 -- a count for each target, kept under the thing itself
endTables in tables
A table's values can be tables. That is how a grid or a list of records is made:
local grid = {
{ 1, 0, 1 },
{ 0, 1, 0 },
}
print(grid[2][2])
local team = {
{ name = "Sky", score = 40 },
{ name = "Moon", score = 90 },
}
table.sort(team, function(a, b)
return a.score > b.score
end)
print(team[1].name)It prints
1
MoonOne table, many names
A variable does not hold a table; it points to one. Giving the table to another variable gives another pointer to the same table:
local a = { 1, 2, 3 }
local b = a
b[1] = 99
print(a[1])
local copy = table.clone(a) -- a table of its own
copy[1] = 0
print(a[1])It prints
99
99The same holds for a table handed to a function: the function can change it. table.clone copies a table one level deep (tables inside it are still shared).
Two tables are equal only if they are the very same table:
print({} == {})It prints
falseHow many
#list counts a list's places from 1 up. Use it for lists that have no gaps. For a table with names as keys it gives 0; table.count counts every value a table has, under any key:
local door = { name = "gate", open = false }
print(#door, table.count(door))It prints
0 2Tables that behave your way
A table can be given a second table, its metatable, which says what should happen when the first is used in ways tables normally cannot be: added, compared, called, or asked for a key it does not have. This is an advanced tool, and most scripts never need it.
The most used entry is __index: where to look when a key is missing. It is what makes the "one function, many tables" pattern from functions work.
local Vector = {}
Vector.__index = Vector -- a key that a vector lacks is looked up in Vector
function Vector.new(x, y)
return setmetatable({ x = x, y = y }, Vector)
end
function Vector:length()
return math.sqrt(self.x ^ 2 + self.y ^ 2)
end
-- What + does for two vectors, and how a vector is shown.
Vector.__add = function(a, b)
return Vector.new(a.x + b.x, a.y + b.y)
end
Vector.__tostring = function(v)
return `({v.x}, {v.y})`
end
local step = Vector.new(3, 4)
print(step:length())
print(tostring(step + step))It prints
5
(6, 8)The entries a metatable can have:
| Entry | Decides |
|---|---|
__index | Reading a key the table lacks (a table to look in, or a function) |
__newindex | Setting a key the table lacks |
__call | Calling the table like a function |
__tostring | What tostring and print show |
__len | What # gives |
__eq __lt __le | ==, < and <= (and with them ~=, > and >=) |
__add __sub __mul __div __mod __pow __idiv __unm | The arithmetic signs (__idiv is //, __unm is the minus before a value) |
__concat | .. |
rawget, rawset, rawequal and rawlen do the plain thing and never ask the metatable.
Next: working with text.