Step 1 of 5 · Reading · ~3 min
Learn
Tables — The One Data Structure
Tables as Arrays
Lua has exactly one container type: the table. No separate array, list, dictionary, set, queue or object — a table is an associative map from keys to values, and when its keys happen to be the integers 1, 2, 3 and so on, it behaves as an array. Every other data structure you will ever build in Lua is a table wearing a costume.
One is the first index
Lua counts from 1, and the whole standard library agrees: #, ipairs, table.insert, table.remove, table.concat and table.sort all assume the first element lives at index 1.
local fruits = {"apple", "banana", "cherry"}
print(fruits[1])
print(fruits[3])
print(#fruits)
--> apple
--> cherry
--> 3
fruits = {"apple", "banana", "cherry"}
key 1 2 3
value "apple" "banana" "cherry"
^
first element — there is no fruits[0]
Reading fruits[0] is not an error. It returns nil, quietly, exactly like any other absent key. That is why a 0-based habit shows up as an arithmetic-on-nil error two lines later instead of as an out-of-bounds message.
Growing and shrinking
local q = {"a", "b", "c"}
table.insert(q, "d")
table.insert(q, 1, "z")
print(table.concat(q, ","))
table.remove(q, 1)
print(table.concat(q, ","))
print(#q)
--> z,a,b,c,d
--> a,b,c,d
--> 4
table.insert(t, v) appends. table.insert(t, pos, v) inserts at pos and shifts everything above it up. table.remove(t, pos) deletes at pos, shifts everything down to close the gap, and returns the value it removed. Writing t[#t + 1] = v appends just as well and is a common sight in real code.
Walking the array
ipairs yields index and value starting at 1, and stops at the first missing index.
local scores = {10, 20, 30}
for i, v in ipairs(scores) do
print(i .. ":" .. v)
end
--> 1:10
--> 2:20
--> 3:30
When you only care about the values, the convention is to name the index _.
local total = 0
for _, v in ipairs(scores) do
total = total + v
end
print(total)
--> 60
What a hole does to a table
Assigning nil does not blank a slot — it removes the key entirely. The table now has a hole, and both # and ipairs stop promising what you want.
local t = {10, 20, 30}
t[2] = nil
for i, v in ipairs(t) do
print(i .. ":" .. v)
end
--> 1:10
t[3] still exists and still holds 30; ipairs simply refuses to step across the gap. #t is murkier still: the manual defines it as a border of the table, and a table with a hole has more than one valid border, so #t may legitimately answer 1 or 3 here. Do not build anything on that answer.
✓ keep sequences dense — delete with table.remove, which closes the gap
✗ t[i] = nil in the middle of a list you still intend to iterate or measure
Tables are references
A table variable holds a reference, not a copy, so two names can point at the same table.
local a = {1, 2}
local b = a
b[1] = 99
print(a[1])
--> 99
Passing a table to a function passes that same reference, which means the function can rewrite your table from the inside. Usually that is exactly what you want; always it is something to remember.
Your exercise
Rotate Left shifts a list of numbers to the left by some number of positions, wrapping the front elements around to the back, and prints the result on one line.
The starter already reads everything into the table nums; you do the rotation and the printing. Three mistakes the grader will catch. Reaching for nums[0] reads nil, because Lua starts at 1. Deleting with nums[i] = nil leaves a hole instead of closing the gap, so everything after it stops being part of the list. And a shift larger than the list length must wrap around: rotating 3 values left by 4 is the same as rotating by 1, so a loop that runs k times unconditionally still works but one that indexes with k directly walks off the end.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…