Lua - Arrays
Overview
Estimated time: 25–30 minutes
Arrays in Lua are implemented using tables with consecutive integer keys starting from 1. This tutorial covers array creation, manipulation, common operations, and algorithms for working with array-like data structures effectively.
Learning Objectives
- Master array creation and initialization techniques
- Learn array manipulation and modification methods
- Understand array iteration patterns and best practices
- Explore multidimensional arrays and nested structures
- Apply common array algorithms and operations
Prerequisites
- Understanding of tables and basic table operations
- Knowledge of loops and iteration
- Familiarity with functions
Array Creation and Initialization
Arrays in Lua are tables with consecutive integer indices starting from 1:
-- Empty array
local empty_array = {}
print("Empty array length:", #empty_array)
-- Array with initial values
local fruits = {"apple", "banana", "orange", "grape"}
print("Fruits array:")
for i = 1, #fruits do
print(i .. ":", fruits[i])
end
-- Array with mixed types (not recommended for pure arrays)
local mixed = {1, "hello", true, 3.14}
print("\nMixed array:")
for i = 1, #mixed do
print(i .. ":", mixed[i], type(mixed[i]))
end
-- Array with explicit indices
local explicit = {
[1] = "first",
[2] = "second",
[3] = "third"
}
print("\nExplicit indices:")
for i = 1, #explicit do
print(i .. ":", explicit[i])
end
-- Creating arrays with table.insert
local numbers = {}
for i = 1, 5 do
table.insert(numbers, i * 2) -- Insert at end
end
print("\nNumbers array:", table.concat(numbers, ", "))
Expected Output:
Empty array length: 0
Fruits array:
1: apple
2: banana
3: orange
4: grape
Mixed array:
1: 1 number
2: hello string
3: true boolean
4: 3.14 number
Explicit indices:
1: first
2: second
3: third
Numbers array: 2, 4, 6, 8, 10
Array Access and Modification
Accessing and modifying array elements:
local colors = {"red", "green", "blue"}
-- Access elements (1-indexed)
print("Array access:")
print("First color:", colors[1])
print("Second color:", colors[2])
print("Last color:", colors[#colors])
-- Modify elements
colors[2] = "yellow" -- Change green to yellow
print("After modification:", table.concat(colors, ", "))
-- Add elements at specific positions
colors[4] = "purple" -- Add at end
print("After adding purple:", table.concat(colors, ", "))
-- Insert element at specific position
table.insert(colors, 2, "orange") -- Insert orange at position 2
print("After inserting orange:", table.concat(colors, ", "))
-- Remove elements
local removed = table.remove(colors, 3) -- Remove element at position 3
print("Removed:", removed)
print("After removal:", table.concat(colors, ", "))
-- Remove last element
local last = table.remove(colors) -- Remove from end
print("Removed last:", last)
print("Final array:", table.concat(colors, ", "))
-- Out of bounds access
print("Element at index 10:", colors[10]) -- Returns nil
print("Array length after operations:", #colors)
Expected Output:
Array access:
First color: red
Second color: green
Last color: blue
After modification: red, yellow, blue
After adding purple: red, yellow, blue, purple
After inserting orange: red, orange, yellow, blue, purple
Removed: yellow
After removal: red, orange, blue, purple
Removed last: purple
Final array: red, orange, blue
Array length after operations: 3
Array Iteration Patterns
Different ways to iterate through arrays:
local numbers = {10, 20, 30, 40, 50}
-- Method 1: Numeric for loop
print("Method 1 - Numeric for loop:")
for i = 1, #numbers do
print("Index " .. i .. ":", numbers[i])
end
-- Method 2: ipairs (recommended for arrays)
print("\nMethod 2 - ipairs:")
for index, value in ipairs(numbers) do
print("Index " .. index .. ":", value)
end
-- Method 3: Generic for with pairs (not recommended for arrays)
print("\nMethod 3 - pairs:")
for key, value in pairs(numbers) do
print("Key " .. key .. ":", value)
end
-- Reverse iteration
print("\nReverse iteration:")
for i = #numbers, 1, -1 do
print("Index " .. i .. ":", numbers[i])
end
-- Iteration with conditions
print("\nValues greater than 25:")
for i, value in ipairs(numbers) do
if value > 25 then
print("Index " .. i .. ":", value)
end
end
-- Finding elements
local function find_value(arr, target)
for i, value in ipairs(arr) do
if value == target then
return i
end
end
return nil
end
local search_value = 30
local found_index = find_value(numbers, search_value)
print("\nFound " .. search_value .. " at index:", found_index or "not found")
Expected Output:
Method 1 - Numeric for loop:
Index 1: 10
Index 2: 20
Index 3: 30
Index 4: 40
Index 5: 50
Method 2 - ipairs:
Index 1: 10
Index 2: 20
Index 3: 30
Index 4: 40
Index 5: 50
Method 3 - pairs:
Key 1: 10
Key 2: 20
Key 3: 30
Key 4: 40
Key 5: 50
Reverse iteration:
Index 5: 50
Index 4: 40
Index 3: 30
Index 2: 20
Index 1: 10
Values greater than 25:
Index 3: 30
Index 4: 40
Index 5: 50
Found 30 at index: 3
Array Operations and Algorithms
Common array operations and algorithms:
Basic Array Operations
-- Array utility functions
local array_utils = {}
-- Copy array (shallow copy)
function array_utils.copy(arr)
local copy = {}
for i, value in ipairs(arr) do
copy[i] = value
end
return copy
end
-- Reverse array in-place
function array_utils.reverse(arr)
local n = #arr
for i = 1, math.floor(n / 2) do
arr[i], arr[n - i + 1] = arr[n - i + 1], arr[i]
end
return arr
end
-- Find maximum value and index
function array_utils.max(arr)
if #arr == 0 then return nil, nil end
local max_val, max_idx = arr[1], 1
for i = 2, #arr do
if arr[i] > max_val then
max_val, max_idx = arr[i], i
end
end
return max_val, max_idx
end
-- Find minimum value and index
function array_utils.min(arr)
if #arr == 0 then return nil, nil end
local min_val, min_idx = arr[1], 1
for i = 2, #arr do
if arr[i] < min_val then
min_val, min_idx = arr[i], i
end
end
return min_val, min_idx
end
-- Sum all elements
function array_utils.sum(arr)
local total = 0
for _, value in ipairs(arr) do
total = total + value
end
return total
end
-- Test the utility functions
local test_array = {3, 1, 4, 1, 5, 9, 2, 6}
print("Original array:", table.concat(test_array, ", "))
local copied = array_utils.copy(test_array)
print("Copied array:", table.concat(copied, ", "))
local max_val, max_idx = array_utils.max(test_array)
print("Maximum value:", max_val, "at index", max_idx)
local min_val, min_idx = array_utils.min(test_array)
print("Minimum value:", min_val, "at index", min_idx)
print("Sum of elements:", array_utils.sum(test_array))
array_utils.reverse(test_array)
print("Reversed array:", table.concat(test_array, ", "))
Expected Output:
Original array: 3, 1, 4, 1, 5, 9, 2, 6
Copied array: 3, 1, 4, 1, 5, 9, 2, 6
Maximum value: 9 at index 6
Minimum value: 1 at index 2
Sum of elements: 31
Reversed array: 6, 2, 9, 5, 1, 4, 1, 3
Searching and Filtering
-- Search and filter operations
local search_utils = {}
-- Linear search
function search_utils.linear_search(arr, target)
for i, value in ipairs(arr) do
if value == target then
return i
end
end
return nil
end
-- Binary search (requires sorted array)
function search_utils.binary_search(arr, target)
local left, right = 1, #arr
while left <= right do
local mid = math.floor((left + right) / 2)
if arr[mid] == target then
return mid
elseif arr[mid] < target then
left = mid + 1
else
right = mid - 1
end
end
return nil
end
-- Filter array elements
function search_utils.filter(arr, predicate)
local result = {}
for _, value in ipairs(arr) do
if predicate(value) then
table.insert(result, value)
end
end
return result
end
-- Find all indices where condition is true
function search_utils.find_all(arr, predicate)
local indices = {}
for i, value in ipairs(arr) do
if predicate(value) then
table.insert(indices, i)
end
end
return indices
end
-- Count elements matching condition
function search_utils.count(arr, predicate)
local count = 0
for _, value in ipairs(arr) do
if predicate(value) then
count = count + 1
end
end
return count
end
-- Test search and filter operations
local test_numbers = {1, 5, 3, 8, 2, 7, 4, 6}
local sorted_numbers = {1, 2, 3, 4, 5, 6, 7, 8}
print("Test array:", table.concat(test_numbers, ", "))
-- Linear search
local target = 7
local found_index = search_utils.linear_search(test_numbers, target)
print("Linear search for " .. target .. ":", found_index)
-- Binary search on sorted array
print("Sorted array:", table.concat(sorted_numbers, ", "))
local binary_index = search_utils.binary_search(sorted_numbers, target)
print("Binary search for " .. target .. ":", binary_index)
-- Filter even numbers
local even_numbers = search_utils.filter(test_numbers, function(x) return x % 2 == 0 end)
print("Even numbers:", table.concat(even_numbers, ", "))
-- Find all indices of numbers > 5
local large_indices = search_utils.find_all(test_numbers, function(x) return x > 5 end)
print("Indices of numbers > 5:", table.concat(large_indices, ", "))
-- Count odd numbers
local odd_count = search_utils.count(test_numbers, function(x) return x % 2 == 1 end)
print("Count of odd numbers:", odd_count)
Expected Output:
Test array: 1, 5, 3, 8, 2, 7, 4, 6
Linear search for 7: 6
Sorted array: 1, 2, 3, 4, 5, 6, 7, 8
Binary search for 7: 7
Even numbers: 8, 2, 4, 6
Indices of numbers > 5: 2, 4, 6, 8
Count of odd numbers: 4
Array Transformation
Transform arrays using mapping and reduction operations:
-- Transformation operations
local transform_utils = {}
-- Map function to each element
function transform_utils.map(arr, func)
local result = {}
for i, value in ipairs(arr) do
result[i] = func(value)
end
return result
end
-- Reduce array to single value
function transform_utils.reduce(arr, func, initial)
local accumulator = initial
for _, value in ipairs(arr) do
accumulator = func(accumulator, value)
end
return accumulator
end
-- Create array with range of values
function transform_utils.range(start, stop, step)
step = step or 1
local result = {}
for i = start, stop, step do
table.insert(result, i)
end
return result
end
-- Flatten nested arrays (one level)
function transform_utils.flatten(arr)
local result = {}
for _, value in ipairs(arr) do
if type(value) == "table" then
for _, nested_value in ipairs(value) do
table.insert(result, nested_value)
end
else
table.insert(result, value)
end
end
return result
end
-- Chunk array into smaller arrays
function transform_utils.chunk(arr, size)
local result = {}
for i = 1, #arr, size do
local chunk = {}
for j = i, math.min(i + size - 1, #arr) do
table.insert(chunk, arr[j])
end
table.insert(result, chunk)
end
return result
end
-- Test transformation operations
local numbers = {1, 2, 3, 4, 5}
print("Original numbers:", table.concat(numbers, ", "))
-- Map: square each number
local squares = transform_utils.map(numbers, function(x) return x * x end)
print("Squared:", table.concat(squares, ", "))
-- Map: convert to strings
local strings = transform_utils.map(numbers, tostring)
print("As strings:", table.concat(strings, ", "))
-- Reduce: sum all numbers
local sum = transform_utils.reduce(numbers, function(acc, x) return acc + x end, 0)
print("Sum using reduce:", sum)
-- Reduce: find maximum
local max = transform_utils.reduce(numbers, function(acc, x) return math.max(acc, x) end, numbers[1])
print("Max using reduce:", max)
-- Range generation
local range1 = transform_utils.range(1, 10)
local range2 = transform_utils.range(0, 20, 3)
print("Range 1-10:", table.concat(range1, ", "))
print("Range 0-20 step 3:", table.concat(range2, ", "))
-- Flatten nested arrays
local nested = {{1, 2}, {3, 4}, {5, 6}}
local flattened = transform_utils.flatten(nested)
print("Flattened:", table.concat(flattened, ", "))
-- Chunk array
local data = {1, 2, 3, 4, 5, 6, 7, 8, 9}
local chunks = transform_utils.chunk(data, 3)
print("Chunked into groups of 3:")
for i, chunk in ipairs(chunks) do
print("Chunk " .. i .. ":", table.concat(chunk, ", "))
end
Expected Output:
Original numbers: 1, 2, 3, 4, 5
Squared: 1, 4, 9, 16, 25
As strings: 1, 2, 3, 4, 5
Sum using reduce: 15
Max using reduce: 5
Range 1-10: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Range 0-20 step 3: 0, 3, 6, 9, 12, 15, 18
Flattened: 1, 2, 3, 4, 5, 6
Chunked into groups of 3:
Chunk 1: 1, 2, 3
Chunk 2: 4, 5, 6
Chunk 3: 7, 8, 9
Multidimensional Arrays
Working with matrices and multidimensional data:
-- 2D array (matrix) operations
local matrix_utils = {}
-- Create 2D array filled with value
function matrix_utils.create(rows, cols, value)
value = value or 0
local matrix = {}
for i = 1, rows do
matrix[i] = {}
for j = 1, cols do
matrix[i][j] = value
end
end
return matrix
end
-- Print 2D array
function matrix_utils.print(matrix)
for i = 1, #matrix do
local row = ""
for j = 1, #matrix[i] do
row = row .. string.format("%4d ", matrix[i][j])
end
print(row)
end
end
-- Get matrix dimensions
function matrix_utils.dimensions(matrix)
local rows = #matrix
local cols = rows > 0 and #matrix[1] or 0
return rows, cols
end
-- Matrix addition
function matrix_utils.add(matrix1, matrix2)
local rows1, cols1 = matrix_utils.dimensions(matrix1)
local rows2, cols2 = matrix_utils.dimensions(matrix2)
if rows1 ~= rows2 or cols1 ~= cols2 then
error("Matrix dimensions must match for addition")
end
local result = matrix_utils.create(rows1, cols1)
for i = 1, rows1 do
for j = 1, cols1 do
result[i][j] = matrix1[i][j] + matrix2[i][j]
end
end
return result
end
-- Transpose matrix
function matrix_utils.transpose(matrix)
local rows, cols = matrix_utils.dimensions(matrix)
local result = matrix_utils.create(cols, rows)
for i = 1, rows do
for j = 1, cols do
result[j][i] = matrix[i][j]
end
end
return result
end
-- Example usage
print("2D Array (Matrix) operations:")
-- Create and fill matrices
local matrix1 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
local matrix2 = {
{9, 8, 7},
{6, 5, 4},
{3, 2, 1}
}
print("Matrix 1:")
matrix_utils.print(matrix1)
print("\nMatrix 2:")
matrix_utils.print(matrix2)
-- Matrix addition
local sum_matrix = matrix_utils.add(matrix1, matrix2)
print("\nMatrix 1 + Matrix 2:")
matrix_utils.print(sum_matrix)
-- Matrix transpose
local transposed = matrix_utils.transpose(matrix1)
print("\nMatrix 1 transposed:")
matrix_utils.print(transposed)
-- Create identity matrix
local identity = matrix_utils.create(3, 3, 0)
for i = 1, 3 do
identity[i][i] = 1
end
print("\n3x3 Identity matrix:")
matrix_utils.print(identity)
-- 3D array example (simple)
local cube = {}
for i = 1, 2 do
cube[i] = {}
for j = 1, 2 do
cube[i][j] = {}
for k = 1, 2 do
cube[i][j][k] = i * 100 + j * 10 + k
end
end
end
print("\n3D array example:")
for i = 1, 2 do
print("Layer " .. i .. ":")
for j = 1, 2 do
local row = ""
for k = 1, 2 do
row = row .. cube[i][j][k] .. " "
end
print(" " .. row)
end
end
Expected Output:
2D Array (Matrix) operations:
Matrix 1:
1 2 3
4 5 6
7 8 9
Matrix 2:
9 8 7
6 5 4
3 2 1
Matrix 1 + Matrix 2:
10 10 10
10 10 10
10 10 10
Matrix 1 transposed:
1 4 7
2 5 8
3 6 9
3x3 Identity matrix:
1 0 0
0 1 0
0 0 1
3D array example:
Layer 1:
111 112
121 122
Layer 2:
211 212
221 222
Sorting Arrays
Built-in and custom sorting algorithms:
-- Sorting examples
local sort_utils = {}
-- Bubble sort (for educational purposes)
function sort_utils.bubble_sort(arr)
local n = #arr
local sorted = {}
-- Copy array
for i = 1, n do
sorted[i] = arr[i]
end
-- Bubble sort algorithm
for i = 1, n - 1 do
for j = 1, n - i do
if sorted[j] > sorted[j + 1] then
sorted[j], sorted[j + 1] = sorted[j + 1], sorted[j]
end
end
end
return sorted
end
-- Built-in sort with custom comparisons
local numbers = {64, 34, 25, 12, 22, 11, 90}
local words = {"banana", "apple", "cherry", "date"}
local people = {
{name = "Alice", age = 30},
{name = "Bob", age = 25},
{name = "Charlie", age = 35}
}
print("Sorting examples:")
print("Original numbers:", table.concat(numbers, ", "))
-- Sort copy using built-in sort
local sorted_numbers = {}
for i, v in ipairs(numbers) do sorted_numbers[i] = v end
table.sort(sorted_numbers)
print("Sorted (ascending):", table.concat(sorted_numbers, ", "))
-- Sort in descending order
local desc_numbers = {}
for i, v in ipairs(numbers) do desc_numbers[i] = v end
table.sort(desc_numbers, function(a, b) return a > b end)
print("Sorted (descending):", table.concat(desc_numbers, ", "))
-- Bubble sort comparison
local bubble_sorted = sort_utils.bubble_sort(numbers)
print("Bubble sort result:", table.concat(bubble_sorted, ", "))
-- Sort strings
local sorted_words = {}
for i, v in ipairs(words) do sorted_words[i] = v end
table.sort(sorted_words)
print("Sorted words:", table.concat(sorted_words, ", "))
-- Sort by length
local by_length = {}
for i, v in ipairs(words) do by_length[i] = v end
table.sort(by_length, function(a, b) return #a < #b end)
print("Sorted by length:", table.concat(by_length, ", "))
-- Sort complex objects
local sorted_people = {}
for i, v in ipairs(people) do sorted_people[i] = v end
table.sort(sorted_people, function(a, b) return a.age < b.age end)
print("People sorted by age:")
for _, person in ipairs(sorted_people) do
print(" " .. person.name .. " (" .. person.age .. ")")
end
Expected Output:
Sorting examples:
Original numbers: 64, 34, 25, 12, 22, 11, 90
Sorted (ascending): 11, 12, 22, 25, 34, 64, 90
Sorted (descending): 90, 64, 34, 25, 22, 12, 11
Bubble sort result: 11, 12, 22, 25, 34, 64, 90
Sorted words: apple, banana, cherry, date
Sorted by length: date, apple, banana, cherry
People sorted by age:
Bob (25)
Alice (30)
Charlie (35)
Common Pitfalls
- 1-indexing: Lua arrays start at index 1, not 0
- Sparse arrays: Arrays with gaps can cause unexpected behavior with
#
- ipairs vs pairs: Use
ipairs
for arrays,pairs
for general tables - Table modifications during iteration: Can cause skipped elements or errors
- Reference vs copy: Array assignments create references, not copies
Checks for Understanding
- What index does the first element of a Lua array have?
- How do you add an element to the end of an array?
- What's the difference between
table.insert(arr, val)
andarr[#arr + 1] = val
? - How do you create a 2D array with 3 rows and 4 columns?
- What function should you use to iterate over array elements?
Show answers
- Index 1 - Lua arrays are 1-indexed
- Use
table.insert(arr, value)
orarr[#arr + 1] = value
- Both do the same thing - add to the end.
table.insert
is more explicit and readable - Create nested loops:
for i=1,3 do arr[i]={} for j=1,4 do arr[i][j]=value end end
- Use
ipairs()
for arrays to ensure proper iteration over consecutive integer keys
Next Steps
Now that you understand arrays and array operations, you're ready to explore iterators and learn advanced iteration patterns for processing collections of data.