Skip to content
AgileLogics
5 min read

Advanced Tables

Prerequisites: The table library

Copying tables

Assignment copies a reference. To copy the contents:

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

local function deepCopy(t)
  if type(t) ~= "table" then return t end
  local copy = {}
  for k, v in pairs(t) do copy[deepCopy(k)] = deepCopy(v) end
  return copy
end

local original = {name = "Ada", tags = {"admin"}}
local shallow = shallowCopy(original)
local deep = deepCopy(original)

original.tags[1] = "changed"
print(shallow.tags[1])
print(deep.tags[1])
changed
admin

A shallow copy shares nested tables; a deep copy duplicates them. (This simple deepCopy doesn't handle tables that contain themselves.)

Stacks and queues

local stack = {}
table.insert(stack, "a")
table.insert(stack, "b")
print(table.remove(stack))

local Queue = {first = 1, last = 0, items = {}}
local function push(q, v) q.last = q.last + 1; q.items[q.last] = v end
local function pop(q)
  if q.first > q.last then return nil end
  local v = q.items[q.first]
  q.items[q.first] = nil
  q.first = q.first + 1
  return v
end

push(Queue, "x"); push(Queue, "y")
print(pop(Queue), pop(Queue), pop(Queue))
b
x	y	nil

table.remove(t, 1) also works as a queue, but it shifts every element; the two-index version above is constant time.

Functional helpers

local function map(t, fn)
  local r = {}
  for i, v in ipairs(t) do r[i] = fn(v) end
  return r
end

local function filter(t, pred)
  local r = {}
  for _, v in ipairs(t) do if pred(v) then r[#r + 1] = v end end
  return r
end

local function reduce(t, fn, acc)
  for _, v in ipairs(t) do acc = fn(acc, v) end
  return acc
end

local nums = {1, 2, 3, 4, 5, 6}
local evens = filter(nums, function(n) return n % 2 == 0 end)
local squares = map(evens, function(n) return n * n end)
print(table.concat(squares, " "))
print(reduce(squares, function(a, b) return a + b end, 0))
4 16 36
56

Lua's standard library has none of these, so most projects write their own small set or use a library such as Penlight.

Grouping

local people = {
  {name = "Ada", city = "London"}, {name = "Linus", city = "Helsinki"},
  {name = "Alan", city = "London"},
}
local byCity = {}
for _, p in ipairs(people) do
  byCity[p.city] = byCity[p.city] or {}
  table.insert(byCity[p.city], p.name)
end
print(table.concat(byCity.London, ", "))
print(#byCity.Helsinki)
Ada, Alan
1