Arrays and Dictionaries: One Type, Two Styles
In many languages, arrays and dictionaries (or hash maps) are distinct types with different performance characteristics and APIs. Lua collapses both concepts into the single table type: an 'array' is simply a table whose keys are the consecutive integers 1, 2, 3, ... n, while a 'dictionary' (or 'hash map') is a table whose keys are arbitrary values such as strings. Internally, the Lua reference implementation actually optimizes this by storing the dense integer-keyed part in a contiguous array segment and everything else in a hash segment, but from the programmer's perspective it is one uniform table.
Cricket analogy: A Test match scorecard numbered ball-by-ball (array style) differs in feel from a player-of-the-tournament awards list keyed by category like 'Best Bowler' (dictionary style), yet both could live in the same physical scorebook, just as Lua stores both under one table type.
Array-Style Tables
An array-style table stores elements under consecutive integer keys starting at 1, such as local fruits = {'apple', 'banana', 'cherry'}, where fruits[1] is 'apple', fruits[2] is 'banana', and so on. The dedicated iterator ipairs(t) is built for this style: it walks i = 1, 2, 3, ... and stops as soon as it hits the first nil, which makes it fast and predictable but also means it will silently ignore anything after a gap. Array-style tables are the natural fit for ordered collections like queues, stacks, and lists where position matters more than named lookup.
Cricket analogy: A batting lineup where positions 1 through 11 must be filled in order is exactly array-style, and ipairs walking the lineup is like an umpire calling out batsmen strictly by number until the lineup sheet shows a blank slot, at which point he stops reading.
Dictionary-Style Tables
A dictionary-style table stores values under keys that are not a dense integer sequence -- most commonly strings -- such as local player = {name = 'Aria', level = 12, class = 'Mage'}. Fields are read with dot or bracket notation, and the whole table is walked with pairs(t), which visits every key regardless of type but makes no guarantee about the order of iteration. Dictionary-style tables are the natural fit for records and configuration objects, where each piece of data has a meaningful name rather than a meaningful position.
Cricket analogy: A player's profile card with named fields like battingAverage and bowlingStyle is dictionary-style, and pairs() reading it is like a broadcaster pulling up stats on screen in whatever order the graphics team queued them, not necessarily alphabetical or chronological.
Mixing Styles and Avoiding Pitfalls
A single table can legitimately combine both styles -- an array of items plus a couple of named metadata fields is common and safe, since ipairs simply ignores the non-integer keys and pairs sees everything. The real danger is creating holes inside the array part, for example {[1] = 'a', [3] = 'c'} with no key 2: ipairs will stop after index 1 and never see 'c', even though the key exists and pairs would find it. Because of this, code that expects array semantics should always build the sequence with table.insert or consecutive assignment, never by skipping indices.
Cricket analogy: A squad list that's mostly numbered 1-15 plus a named captain field is safe mixing, but leaving jersey number 7 vacant while filling 8 breaks a strict roll-call: the announcer (ipairs) stops at 6 and never reaches 8, even though the selectors (pairs) know player 8 exists.
-- Array-style table
local fruits = {"apple", "banana", "cherry"}
for i, v in ipairs(fruits) do
print(i, v)
end
-- 1 apple
-- 2 banana
-- 3 cherry
-- Dictionary-style table
local player = { name = "Aria", level = 12, class = "Mage" }
for k, v in pairs(player) do
print(k, v) -- order not guaranteed
end
-- Mixed table: safe
local inventory = {"sword", "shield", owner = "Aria"}
print(#inventory) --> 2
print(inventory.owner) --> Aria
-- DANGEROUS: a hole in the array part
local broken = {[1] = "a", [3] = "c"}
for i, v in ipairs(broken) do
print(i, v) -- prints only "1 a", never reaches index 3
end
ipairs silently stops at the first nil hole in the array part, even though the key beyond the hole still exists in the table. If you build sequences by assigning to arbitrary indices instead of using table.insert or consecutive assignment starting at 1, code that relies on ipairs or the # operator can quietly drop data with no error raised.
- Lua uses one table type for both arrays (dense integer keys from 1) and dictionaries (arbitrary keys, often strings).
- ipairs(t) iterates the array part in order and stops at the first nil; pairs(t) visits every key in unspecified order.
- Array-style tables suit ordered data like queues and lists; dictionary-style tables suit named records and configuration.
- Combining an array part with a few named fields in the same table is common and safe.
- Creating a hole in the integer keys breaks ipairs and the # operator even though pairs still sees the data.
- Always build sequences with table.insert or consecutive index assignment to avoid accidental holes.
Practice what you learned
1. What does ipairs(t) do when it encounters a nil at index 4 in an otherwise populated table?
2. Which of these is a dictionary-style Lua table?
3. What is guaranteed about the order in which pairs(t) visits a table's keys?
4. What is the length (#) of the table {name = 'Aria', class = 'Mage'}?
5. Which practice safely avoids holes when building an array-style table incrementally?
Was this page helpful?
You May Also Like
Tables in Lua
Learn how Lua's single, versatile data structure -- the table -- powers arrays, dictionaries, objects, and modules across every Lua program.
Metatables Explained
Discover how Lua metatables let ordinary tables gain custom behavior for indexing, inheritance, and protection, powering nearly every advanced Lua idiom.
String Library in Lua
Master Lua's built-in string library -- immutable strings, extraction, case conversion, lightweight pattern matching, and formatted output.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics