Lua Tables Guide — Arrays, Dictionaries, and Mixed Data Structures
In this tutorial, you will learn about Lua Tables Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Lua tables are the single data structure that serves as arrays, dictionaries, objects, modules, and sets -- combining associative array semantics with array-like indexed access into one flexible container.
What You'll Learn
- Creating and accessing tables as arrays and dictionaries
- 1-based indexing and the length operator
- Mixed tables with both integer and string keys
- Table manipulation functions in the standard library
Why It Matters
Tables are the foundation of every Lua program. Understanding tables means understanding Lua -- OOP, metatables, modules, and even environments all use tables. Mastering tables makes every other Lua concept easier to learn.
Real-World Use
A Redis Lua script uses a table to store multiple keys and values returned from a hash operation. A Love2D game uses tables to store all game objects, their positions, and properties. A configuration parser stores its entire parsed result in a nested table.
flowchart LR
A["Tables"] --> B["Array Style"]
A --> C["Dict Style"]
A --> D["Mixed Style"]
B --> E["Operations"]
C --> E
D --> E
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Creating Tables
Tables are created with curly braces {}.
-- Empty table
local t = {}
-- Array-style table (implicit integer keys)
local fruits = {"apple", "banana", "cherry"}
-- Dictionary-style table (explicit keys)
local person = {
name = "Alice",
age = 30,
job = "Engineer"
}
-- Mixed table
local mixed = {
"first",
"second",
key = "value",
[10] = "ten",
["nested"] = {1, 2, 3}
}
Array-Style Access
Arrays are 1-indexed in Lua. The first element is at index 1.
local colors = {"red", "green", "blue"}
-- Access by index (1-based)
print(colors[1]) --> red
print(colors[2]) --> green
print(colors[3]) --> blue
-- Length operator
print(#colors) --> 3
-- Adding elements
colors[4] = "yellow"
colors[#colors + 1] = "purple"
print(#colors) --> 5
-- Iterating
for i = 1, #colors do
print(i, colors[i])
end
Expected output:
red
green
blue
3
5
1 red
2 green
3 blue
4 yellow
5 purple
Important: 1-Indexed
Lua arrays start at 1, not 0. This is a common source of bugs for developers coming from most other languages.
local arr = {10, 20, 30}
print(arr[0]) --> nil (no error, just nil!)
print(arr[1]) --> 10
Dictionary-Style Access
Tables can use strings, numbers, or any value as keys.
local config = {
host = "localhost",
port = 8080,
debug = true
}
-- Dot notation (for string keys)
print(config.host) --> localhost
print(config.port) --> 8080
-- Bracket notation (for any key type)
print(config["host"]) --> localhost
print(config["port"]) --> 8080
-- Adding new keys
config.timeout = 5000
config["retries"] = 3
-- Checking existence
if config.debug then
print("Debug mode is on")
end
Mixed Tables
Tables can mix array and dictionary parts freely.
local data = {
"alpha", -- [1] = "alpha"
"beta", -- [2] = "beta"
name = "test", -- ["name"] = "test"
[5] = "five", -- explicit key
"gamma" -- [3] = "gamma" (continues from 3)
}
print(data[1]) --> alpha
print(data[2]) --> beta
print(data[3]) --> gamma
print(data.name) --> test
print(data[5]) --> five
Length of Mixed Tables
The # operator only counts the array part (contiguous integer keys from 1).
local t = {10, 20, nil, 40}
print(#t) --> ? (undefined behavior -- table has a hole at 3)
local t2 = {a = 1, b = 2}
print(#t2) --> 0 (dictionary part not counted)
Nested Tables
Tables can contain other tables, creating complex data structures.
local matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
print(matrix[2][3]) --> 6
local inventory = {
player = {
name = "Hero",
items = {"sword", "shield", "potion"}
},
chest = {
gold = 100,
items = {"key", "map"}
}
}
print(inventory.player.items[1]) --> sword
Table Library Functions
local t = {3, 1, 4, 1, 5, 9}
-- Insert at end
table.insert(t, 2)
--> {3, 1, 4, 1, 5, 9, 2}
-- Insert at position
table.insert(t, 1, 100)
--> {100, 3, 1, 4, 1, 5, 9, 2}
-- Remove and return last element
local last = table.remove(t)
print(last) --> 2
-- Remove from position
local first = table.remove(t, 1)
print(first) --> 100
-- Sort (in-place)
table.sort(t)
--> {1, 1, 3, 4, 5, 9}
-- Concatenate
local words = {"Lua", "is", "great"}
print(table.concat(words, " ")) --> Lua is great
print(table.concat(words, ", ", 1, 2)) --> Lua, is
Iterating Over Tables
local t = {a = 1, b = 2, c = 3}
-- pairs() iterates all key-value pairs
for key, value in pairs(t) do
print(key, value)
end
-- ipairs() iterates integer keys from 1
local arr = {10, 20, 30}
for index, value in ipairs(arr) do
print(index, value)
end
Common Mistakes
1. Using index 0 instead of 1
fruits[0] returns nil. Always start loops at 1. This is the most common Lua bug.
2. Assuming tables copy by value
local t2 = t1 creates an alias, not a copy. Use table.clone (Lua 5.4+) or a loop for deep copies.
3. Modifying tables while iterating
Adding or removing keys during pairs() iteration produces undefined behavior. Collect keys first, then modify.
4. Expecting # to work on dictionaries
The # operator only counts the array part (contiguous 1-based integer keys). It returns 0 for pure dictionaries.
5. Assuming insertion order is preserved
pairs() does NOT guarantee iteration order (though Lua 5.4 preserves it for performance). Use ipairs for ordered arrays.
Practice Questions
1. What is the value of arr[0] in Lua when arr = {10, 20, 30}?
nil. Lua arrays start at 1, so index 0 is not a valid entry.
2. How do you add an element to the end of an array?
Use table.insert(arr, value) or arr[#arr + 1] = value.
3. What is the difference between pairs() and ipairs()?
ipairs() iterates integer keys from 1 sequentially. pairs() iterates all key-value pairs. Use ipairs for arrays and pairs for dictionaries.
Challenge: Create a table representing a student database with at least 3 students. Each student has name, age, and grades (a table of subjects and scores). Print each student's name and average grade.
FAQ
{{< faq question="Why does Lua use 1-based indexing?" >}} Lua was designed for non-programmers (domain experts, artists) who naturally count from 1. The designers prioritized approachability over convention. {{< /faq >}}
{{< faq question="Can tables have non-string or non-integer keys?" >}} Yes. Tables can use any value as a key except nil. This includes booleans, functions, and other tables as keys. {{< /faq >}}
{{< faq question="How do I copy a table?" >}}
For shallow copy in Lua 5.4+: local copy = table.clone(original). For deep copy, use a recursive function that creates new tables for nested tables.
{{< /faq >}}
{{< faq question="Is a table an array or a hash map?" >}} Both. Lua tables use a hybrid implementation -- the array part stores contiguous integer keys from 1, and the hash part stores everything else. This makes them efficient as both arrays and dictionaries. {{< /faq >}}
{{< faq question="How do I check if a table is empty?" >}}
Use next(t) == nil. If next(t) returns nil, the table has no elements. Using #t == 0 only checks the array part.
{{< /faq >}}
Try It Yourself
local shopping_list = {"milk", "bread", "eggs", "cheese"}
-- Add items
shopping_list[#shopping_list + 1] = "butter"
-- Display all items
print("Shopping List (" .. #shopping_list .. " items):")
for i, item in ipairs(shopping_list) do
print(i .. ". " .. item)
end
-- Find an item
local target = "eggs"
for i, item in ipairs(shopping_list) do
if item == target then
print(target .. " is at position " .. i)
break
end
end
Expected output:
Shopping List (5 items):
1. milk
2. bread
3. eggs
4. cheese
5. butter
eggs is at position 3
What's Next
Now that you understand tables, learn how functions work in Lua -- including first-class functions, closures, and varargs.
| Topic | Description | Link |
|---|---|---|
| Functions | First-class functions and closures | {{< ref "05-functions" >}} |
| Metatables | Operator overloading and inheritance | {{< ref "06-metatables" >}} |
| Python Lists | Compare with Python lists and dicts | Python |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro