Web Analytics

Tables in Lua

Beginner ~30 min read

Tables are Lua's only data structuring mechanism, but don't let that fool youβ€”they're incredibly versatile! Tables can be used as arrays, dictionaries, sets, objects, modules, and more. Understanding tables is essential to mastering Lua. In this lesson, you'll learn everything about creating, accessing, and manipulating tables. Let's dive in!

Creating Tables

Tables are created using curly braces {}:

-- Empty table
local empty = {}

-- Table with values
local numbers = {10, 20, 30, 40, 50}

-- Table with key-value pairs
local person = {
    name = "Alice",
    age = 25,
    city = "New York"
}
Important: Lua tables use 1-based indexing for arrays, not 0-based like most languages. The first element is at index 1!
Output
Click Run to execute your code

Tables as Arrays

Use tables with numeric indices as arrays:

local fruits = {"apple", "banana", "cherry"}

-- Access elements (1-based!)
print(fruits[1])  -- apple
print(fruits[2])  -- banana
print(fruits[3])  -- cherry

-- Get length
print(#fruits)  -- 3

-- Modify elements
fruits[2] = "blueberry"
print(fruits[2])  -- blueberry

-- Add elements
fruits[4] = "date"
table.insert(fruits, "elderberry")  -- Append to end
Warning: Arrays must have consecutive indices starting from 1. Gaps in indices can cause # to return unexpected results!
Output
Click Run to execute your code

Tables as Dictionaries

Use tables with string keys as dictionaries (hash maps):

local person = {
    name = "Alice",
    age = 25,
    city = "New York"
}

-- Access with dot notation
print(person.name)  -- Alice
print(person.age)   -- 25

-- Access with bracket notation
print(person["city"])  -- New York

-- Add new fields
person.email = "[email protected]"
person["phone"] = "555-1234"

-- Modify fields
person.age = 26

Dot vs Bracket Notation

Notation Use When Example
Dot Key is a valid identifier person.name
Bracket Key has spaces, special chars, or is dynamic person["first name"]
Output
Click Run to execute your code

Mixed Tables

Tables can have both numeric and string keys:

local mixed = {
    "first",      -- [1]
    "second",     -- [2]
    name = "Alice",
    age = 25,
    "third"       -- [3]
}

print(mixed[1])      -- first
print(mixed[2])      -- second
print(mixed[3])      -- third
print(mixed.name)    -- Alice
print(mixed.age)     -- 25
print(#mixed)        -- 3 (only counts numeric indices)
Tip: While mixed tables are possible, it's usually clearer to keep arrays and dictionaries separate for better code readability.

Nested Tables

Tables can contain other tables:

local company = {
    name = "Tech Corp",
    employees = {
        {name = "Alice", role = "Developer"},
        {name = "Bob", role = "Designer"},
        {name = "Charlie", role = "Manager"}
    },
    location = {
        city = "San Francisco",
        state = "CA",
        coordinates = {
            lat = 37.7749,
            lon = -122.4194
        }
    }
}

-- Access nested values
print(company.name)                      -- Tech Corp
print(company.employees[1].name)         -- Alice
print(company.location.city)             -- San Francisco
print(company.location.coordinates.lat)  -- 37.7749
Output
Click Run to execute your code

Iterating Over Tables

Arrays with ipairs

local fruits = {"apple", "banana", "cherry"}

for index, value in ipairs(fruits) do
    print(index, value)
end
-- Output:
-- 1    apple
-- 2    banana
-- 3    cherry

Dictionaries with pairs

local person = {
    name = "Alice",
    age = 25,
    city = "New York"
}

for key, value in pairs(person) do
    print(key, value)
end
-- Output (order not guaranteed):
-- name    Alice
-- age     25
-- city    New York
Remember:
  • ipairs: For arrays (numeric indices), guaranteed order
  • pairs: For all tables, no guaranteed order

Common Table Operations

Checking if Key Exists

local person = {name = "Alice", age = 25}

if person.name then
    print("Name exists")
end

if person.email == nil then
    print("Email does not exist")
end

Removing Elements

local person = {name = "Alice", age = 25, city = "NYC"}

-- Set to nil to remove
person.city = nil

-- For arrays, use table.remove
local fruits = {"apple", "banana", "cherry"}
table.remove(fruits, 2)  -- Remove "banana"
-- fruits = {"apple", "cherry"}

Copying Tables

-- Shallow copy
local function shallowCopy(t)
    local copy = {}
    for k, v in pairs(t) do
        copy[k] = v
    end
    return copy
end

local original = {a = 1, b = 2}
local copy = shallowCopy(original)

-- Deep copy (for nested tables)
local function deepCopy(t)
    if type(t) ~= "table" then
        return t
    end
    local copy = {}
    for k, v in pairs(t) do
        copy[k] = deepCopy(v)
    end
    return copy
end
Output
Click Run to execute your code

Tables as Objects

Tables can store functions, making them behave like objects:

local calculator = {
    value = 0,
    
    add = function(self, x)
        self.value = self.value + x
        return self
    end,
    
    subtract = function(self, x)
        self.value = self.value - x
        return self
    end,
    
    getResult = function(self)
        return self.value
    end
}

-- Using the object
calculator:add(10)
calculator:subtract(3)
print(calculator:getResult())  -- 7
Tip: The colon : syntax automatically passes the table as the first argument (self). obj:method() is equivalent to obj.method(obj).

Practice Exercise

Try these table challenges:

Output
Click Run to execute your code

Summary

In this lesson, you learned:

  • Creating tables with {}
  • Using tables as arrays (1-based indexing!)
  • Using tables as dictionaries with string keys
  • Mixed tables with both numeric and string keys
  • Nested tables for complex data structures
  • Iterating with ipairs and pairs
  • Common operations: checking keys, removing, copying
  • Tables as objects with functions

What's Next?

Now that you understand table basics, it's time to explore the table library! In the next lesson, you'll learn powerful built-in functions for manipulating tables: insert, remove, sort, concat, and more. Let's continue! πŸš€