Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Lua Dictionary
  3. Table Basics

Table Basics

The Lua table is the only data structure in the language — it serves as an array, an associative array, and an object all at once. When used as an array, it is treated as a sequence table with integer keys, and the most distinctive feature is that indices start at 1 (1-indexed), unlike most other languages. This page covers table creation, element access, adding and removing elements, getting the length, and ordered iteration with ipairs.

Syntax

-- -----------------------------------------------
-- Creating a table (table literal)
-- -----------------------------------------------
local t = { value1, value2, value3 }   -- integer keys 1, 2, 3 are assigned automatically

-- -----------------------------------------------
-- Index access (1-indexed)
-- -----------------------------------------------
t[1]          -- first element (indices start at 1, not 0)
t[#t]         -- last element (# operator returns the sequence length)

-- -----------------------------------------------
-- Adding elements
-- -----------------------------------------------
t[#t + 1] = value          -- idiomatic way to append to the end
table.insert(t, value)     -- standard library function also appends to the end
table.insert(t, i, value)  -- inserts at index i

-- -----------------------------------------------
-- Removing elements
-- -----------------------------------------------
table.remove(t)         -- removes and returns the last element
table.remove(t, i)      -- removes and returns the element at index i
t[i] = nil              -- assigning nil leaves a hole (breaks the sequence)

-- -----------------------------------------------
-- Getting the length
-- -----------------------------------------------
#t                      -- returns the length of the sequence (contiguous integer keys)

-- -----------------------------------------------
-- Looping with for ipairs
-- -----------------------------------------------
for i, v in ipairs(t) do
    -- i is the index, v is the value
    -- the loop stops when nil is reached
end

Operation Reference

OperationDescription
{ value1, value2, ... }Creates an array using a table literal. Indices are auto-numbered starting from 1.
t[1]Retrieves the element at index 1. Lua indices start at 1.
t[i] = valueAssigns a value to index i. Assigning to a new index adds an element.
#tReturns the sequence length (number of contiguous integer keys).
t[#t + 1] = valueIdiomatic way to append an element to the end.
table.insert(t, value)Appends an element to the end of the table.
table.insert(t, i, value)Inserts an element at index i, shifting all subsequent elements back.
table.remove(t)Removes and returns the last element.
table.remove(t, i)Removes and returns the element at index i, shifting all subsequent elements forward.
t[i] = nilSets index i to nil. This leaves a hole, making # and ipairs behave unpredictably.
for i, v in ipairs(t)Iterates from index 1 in order. The loop stops when nil is reached.

Sample Code

jjk_table_basic.lua
-- jjk_table_basic.lua — sample for basic table operations
-- Uses Jujutsu Kaisen characters to demonstrate array operations on tables

-- -----------------------------------------------
-- Creating a table (table literal)
-- Indices start at 1 (1-indexed)
-- -----------------------------------------------
local sorcerers = { "Gojo Satoru", "Itadori Yuji", "Kugisaki Nobara", "Fushiguro Megumi" }

print("=== Basic Table Operations ===")
print("")

-- -----------------------------------------------
-- Index access
-- t[1] is the first element (not 0)
-- -----------------------------------------------
print("--- Index access ---")
print("t[1]: " .. sorcerers[1])   -- Gojo Satoru (first element)
print("t[2]: " .. sorcerers[2])   -- Itadori Yuji
print("t[4]: " .. sorcerers[4])   -- Fushiguro Megumi (last element)
print("")

-- -----------------------------------------------
-- Getting the sequence length with #
-- -----------------------------------------------
print("--- Table length ---")
print("Initial count: " .. #sorcerers)   -- 4
print("")

-- -----------------------------------------------
-- Adding elements (two ways to append)
-- -----------------------------------------------
print("--- Adding elements ---")

-- Method 1: idiomatic t[#t + 1] = value
sorcerers[#sorcerers + 1] = "Geto Suguru"
print("Added with t[#t+1]: " .. sorcerers[5])  -- Geto Suguru

-- Method 2: table.insert
table.insert(sorcerers, "Okkotsu Yuta")
print("Added with table.insert: " .. sorcerers[6])  -- Okkotsu Yuta
print("Count after adding: " .. #sorcerers)           -- 6
print("")

-- -----------------------------------------------
-- Inserting at a specific position
-- table.insert(t, i, value) inserts at index i
-- -----------------------------------------------
print("--- Inserting at a specific position ---")
-- Insert "Nanami Kento" at position 2
table.insert(sorcerers, 2, "Nanami Kento")
print("t[1]: " .. sorcerers[1])   -- Gojo Satoru (unchanged)
print("t[2]: " .. sorcerers[2])   -- Nanami Kento (newly inserted)
print("t[3]: " .. sorcerers[3])   -- Itadori Yuji (shifted back)
print("Count: " .. #sorcerers)    -- 7
print("")

-- -----------------------------------------------
-- Looping with for ipairs
-- Iterates from index 1 in order
-- -----------------------------------------------
print("--- Loop with ipairs ---")
for i, name in ipairs(sorcerers) do
    print(string.format("  [%d] %s", i, name))
end
print("")

-- -----------------------------------------------
-- Removing elements
-- table.remove(t, i) removes the element at index i
-- -----------------------------------------------
print("--- Removing elements ---")

-- Remove index 2 (Nanami Kento)
local removed = table.remove(sorcerers, 2)
print("Removed element: " .. removed)          -- Nanami Kento
print("t[2] after removal: " .. sorcerers[2])  -- Itadori Yuji (shifted forward)
print("Count after removal: " .. #sorcerers)   -- 6

-- Remove the last element
local last = table.remove(sorcerers)
print("Removed from end: " .. last)            -- Okkotsu Yuta
print("Final count: " .. #sorcerers)           -- 5
print("")

-- -----------------------------------------------
-- Removing by nil assignment (watch out for sequence breakage)
-- -----------------------------------------------
print("--- Caution with nil assignment ---")
local test = { "Cursed Spirit A", "Cursed Spirit B", "Cursed Spirit C" }
print("Length before nil assignment: " .. #test)   -- 3
test[2] = nil                          -- leaving a hole in the middle breaks the sequence
-- the result of #test is implementation-defined (may return 1 or 3)
print("Length after nil assignment (undefined): " .. #test)
print("ipairs stops before nil in the middle")

local count = 0
for i, v in ipairs(test) do
    count = count + 1
end
print("Count via ipairs: " .. count)   -- 1 (loop ends at t[2]=nil)
lua jjk_table_basic.lua
=== Basic Table Operations ===

--- Index access ---
t[1]: Gojo Satoru
t[2]: Itadori Yuji
t[4]: Fushiguro Megumi

--- Table length ---
Initial count: 4

--- Adding elements ---
Added with t[#t+1]: Geto Suguru
Added with table.insert: Okkotsu Yuta
Count after adding: 6

--- Inserting at a specific position ---
t[1]: Gojo Satoru
t[2]: Nanami Kento
t[3]: Itadori Yuji
Count: 7

--- Loop with ipairs ---
  [1] Gojo Satoru
  [2] Nanami Kento
  [3] Itadori Yuji
  [4] Kugisaki Nobara
  [5] Fushiguro Megumi
  [6] Geto Suguru
  [7] Okkotsu Yuta

--- Removing elements ---
Removed element: Nanami Kento
t[2] after removal: Itadori Yuji
Count after removal: 6
Removed from end: Okkotsu Yuta
Final count: 5

--- Caution with nil assignment ---
Length before nil assignment: 3
Length after nil assignment (undefined): 1
ipairs stops before nil in the middle
Count via ipairs: 1

Common Mistakes

Common Mistake 1: Accessing index 0 and getting nil

In many languages (C, Java, Python, etc.) array indices start at 0, but in Lua they start at 1. Accessing index 0 returns nil without an error, making this a subtle bug that is easy to miss.

ng_index.lua
local sorcerers = { "Gojo Satoru", "Itadori Yuji", "Fushiguro Megumi" }

-- Accessing from 0 as in other languages
print(sorcerers[0])   -- nil (no error, just nil)
print(sorcerers[1])   -- Gojo Satoru
nil
Gojo Satoru

Lua indices start at 1. The first element is t[1] and the last is t[#t].

ok_index.lua
local sorcerers = { "Gojo Satoru", "Itadori Yuji", "Fushiguro Megumi" }

-- Lua is 1-indexed
print(sorcerers[1])            -- Gojo Satoru (first element)
print(sorcerers[#sorcerers])   -- Fushiguro Megumi (last element)
Gojo Satoru
Fushiguro Megumi

Common Mistake 2: Breaking the sequence with t[i] = nil

Assigning t[i] = nil looks like it removes the element, but it actually leaves a hole in the sequence. After this, the value of #t becomes undefined and ipairs will stop early. Use table.remove(t, i) to delete elements while keeping the sequence intact.

ng_nil_assign.lua
local sorcerers = { "Gojo Satoru", "Itadori Yuji", "Kugisaki Nobara", "Fushiguro Megumi" }

-- Assigning nil creates a hole in the sequence
sorcerers[2] = nil

-- #t becomes undefined, ipairs stops early
print("Length (undefined): " .. #sorcerers)

local count = 0
for i, v in ipairs(sorcerers) do
    count = count + 1
end
print("Count via ipairs: " .. count)   -- 1 (loop ends when nil is reached at index 2)
Length (undefined): 1
Count via ipairs: 1

Using table.remove(t, i) shifts the indices and keeps the sequence contiguous.

ok_nil_assign.lua
local sorcerers = { "Gojo Satoru", "Itadori Yuji", "Kugisaki Nobara", "Fushiguro Megumi" }

-- table.remove keeps the sequence intact
local removed = table.remove(sorcerers, 2)
print("Removed: " .. removed)
print("Length: " .. #sorcerers)   -- 3 (works correctly)

for i, v in ipairs(sorcerers) do
    print(string.format("  [%d] %s", i, v))
end
Removed: Itadori Yuji
Length: 3
  [1] Gojo Satoru
  [2] Kugisaki Nobara
  [3] Fushiguro Megumi

Overview

When using a Lua table as an array, the most distinctive feature compared to many other languages (C, Java, Python, etc.) is that indices start at 1 (1-indexed). A table literal { value1, value2, ... } auto-numbers the integer keys 1, 2, 3, and so on. The element count is obtained with #t. To append to the end, either t[#t + 1] = value or table.insert(t, value) can be used. For inserting or removing at a specific position, table.insert(t, i, value) and table.remove(t, i) automatically shift the surrounding elements. For ordered iteration, use for i, v in ipairs(t), but note that if nil appears in the middle the loop stops there, so use table.remove rather than nil assignment to keep the sequence contiguous. For using tables as associative arrays, see also Table as Associative Array.

If you find any errors or copyright issues, please .