Tables in Lua

Tables are Lua’s only data structure, and they’re incredibly versatile. Tables can be used as arrays, dictionaries, objects, and more. Understanding tables is essential for effective Lua programming.

Creating Tables

Tables are created using curly braces {}:

-- Empty table
local empty_table = {}

-- Table with initial values
local fruits = {"apple", "banana", "orange"}
local person = {name = "Alice", age = 30}

Arrays (Numeric Index)

Tables with consecutive numeric keys act as arrays:

local colors = {"red", "green", "blue"}

-- Access by index (Lua arrays are 1-indexed)
print(colors[1])  -- red
print(colors[2])  -- green
print(colors[3])  -- blue

-- Add new element
colors[4] = "yellow"
print(colors[4])  -- yellow

-- Get array length
print(#colors)  -- 4

Array Operations

local numbers = {10, 20, 30, 40, 50}

-- Iterate over array
for i, value in ipairs(numbers) do
    print(i, value)
end

-- Add to end
table.insert(numbers, 60)
print(#numbers)  -- 6

-- Remove from end
local removed = table.remove(numbers)
print(removed)   -- 60
print(#numbers)  -- 5

-- Insert at specific position
table.insert(numbers, 3, 25)  -- Insert 25 at position 3
-- numbers is now: {10, 20, 25, 30, 40, 50}

-- Remove at specific position
table.remove(numbers, 2)  -- Remove element at position 2
-- numbers is now: {10, 25, 30, 40, 50}

Dictionaries (Key-Value Pairs)

Tables with string keys act as dictionaries:

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

-- Access values
print(person.name)        -- Alice
print(person["age"])      -- 30

-- Modify values
person.age = 31
person.city = "Boston"

-- Add new key-value pairs
person.job = "Engineer"

-- Iterate over dictionary
for key, value in pairs(person) do
    print(key, ":", value)
end

Dynamic Key Names

local data = {}

-- Using variables as keys
local key1 = "username"
local key2 = "score"

data[key1] = "john_doe"
data[key2] = 1500

print(data.username)  -- john_doe
print(data.score)     -- 1500

-- Keys can be any type except nil
local mixed_keys = {
    [1] = "numeric key",
    ["string"] = "string key",
    [true] = "boolean key"
}

for key, value in pairs(mixed_keys) do
    print(type(key), key, ":", value)
end

Mixed Tables

Tables can contain both array and dictionary elements:

local mixed = {
    "first",     -- array element [1]
    "second",    -- array element [2]
    name = "Test",  -- dictionary element
    "third",     -- array element [3] (because nil name doesn't count as array)
    age = 25     -- dictionary element
}

-- Array part
for i, value in ipairs(mixed) do
    print("Array", i, ":", value)
end

-- Dictionary part
for key, value in pairs(mixed) do
    if type(key) == "string" then
        print("Dict", key, ":", value)
    end
end

Table Operations

Table Manipulation Functions

local numbers = {3, 1, 4, 1, 5, 9, 2, 6}

-- Sort array
table.sort(numbers)
print(table.concat(numbers, ", "))  -- 1, 1, 2, 3, 4, 5, 6, 9

-- Custom sort
local people = {
    {name = "Alice", age = 30},
    {name = "Bob", age = 25},
    {name = "Charlie", age = 35}
}

table.sort(people, function(a, b)
    return a.age < b.age
end)

for i, person in ipairs(people) do
    print(i, person.name, person.age)
end
-- 1 Bob 25
-- 2 Alice 30
-- 3 Charlie 35

Checking for Elements

function table_contains(table, element)
    for _, value in pairs(table) do
        if value == element then
            return true
        end
    end
    return false
end

local fruits = {"apple", "banana", "orange"}
print(table_contains(fruits, "banana"))   -- true
print(table_contains(fruits, "grape"))     -- false

Merging Tables

function merge_tables(t1, t2)
    local result = {}
    for k, v in pairs(t1) do result[k] = v end
    for k, v in pairs(t2) do result[k] = v end
    return result
end

local defaults = {color = "blue", size = "medium"}
local settings = {size = "large", style = "bold"}
local merged = merge_tables(defaults, settings)

for k, v in pairs(merged) do
    print(k, v)
end
-- color blue
-- size large (overwrites default)
-- style bold

Advanced Table Usage

Objects and Methods

-- Object-like table with methods
local counter = {
    value = 0,
    increment = function(self)
        self.value = self.value + 1
    end,
    get_value = function(self)
        return self.value
    end,
    reset = function(self)
        self.value = 0
    end
}

counter:increment()
counter:increment()
print(counter:get_value())  -- 2
counter:reset()
print(counter:get_value())  -- 0

Metatables (Advanced)

-- Create a table with custom behavior
local vector = {
    x = 0,
    y = 0
}

local vector_metatable = {
    __add = function(a, b)
        return {
            x = a.x + b.x,
            y = a.y + b.y
        }
    end,
    __tostring = function(v)
        return "(" .. v.x .. ", " .. v.y .. ")"
    end
}

setmetatable(vector, vector_metatable)

-- Create vectors
local v1 = {x = 1, y = 2}
local v2 = {x = 3, y = 4}

setmetatable(v1, vector_metatable)
setmetatable(v2, vector_metatable)

local v3 = v1 + v2
print(tostring(v3))  -- (4, 6)

Practical Examples

Configuration Table

local config = {
    database = {
        host = "localhost",
        port = 5432,
        name = "myapp"
    },
    server = {
        port = 8080,
        host = "0.0.0.0"
    },
    features = {
        authentication = true,
        logging = true,
        debug = false
    }
}

-- Access nested configuration
print(config.database.host)      -- localhost
print(config.server.port)        -- 8080
print(config.features.auth)  -- true

Data Processing Pipeline

local users = {
    {id = 1, name = "Alice", score = 85},
    {id = 2, name = "Bob", score = 92},
    {id = 3, name = "Charlie", score = 78},
    {id = 4, name = "Diana", score = 95}
}

-- Filter high scorers
local high_scorers = {}
for _, user in ipairs(users) do
    if user.score >= 90 then
        table.insert(high_scorers, user)
    end
end

-- Sort by score
table.sort(high_scorers, function(a, b)
    return a.score > b.score
end)

-- Display results
for i, user in ipairs(high_scorers) do
    print(i, user.name, user.score)
end
-- 1 Diana 95
-- 2 Bob 92

Simple Cache System

local cache = {
    data = {},
    get = function(self, key)
        return self.data[key]
    end,
    set = function(self, key, value)
        self.data[key] = value
    end,
    has = function(self, key)
        return self.data[key] ~= nil
    end
}

-- Usage
cache:set("user:1", {name = "Alice", age = 30})
print(cache:has("user:1"))  -- true
local user = cache:get("user:1")
print(user.name)  -- Alice

Best Practices

  1. Use appropriate data structures (arrays vs dictionaries)
  2. Keep tables simple when possible
  3. Use meaningful keys and consistent naming
  4. Consider performance for large tables
  5. Use ipairs for arrays and pairs for dictionaries
  6. Initialize tables properly before use

Next Steps

Now that you understand tables, learn about strings to work with text data effectively.

For more table details, see the Lua manual.

Last updated on