A data structure is a storage format for organizing, processing, and retrieving data.
To use an analogy, think of a filing cabinet.
Filing cabinets have a way in which documents are stored and organized. Cabinets can slide in and out for retrieving documents. It might have a lock to limit access to its contents. You can move the entire filing cabinet around while keeping its contents organized.
There exists many different types of data structures, each with their own advantages and disadvantages. Lua, in keeping with its lightweight paradigm, has one type of data structure: the table.
But don’t feel like this will limit you. Lua’s table was designed to be a building block for creating other structures and other data types. As you continue on your development journey, you will see that Lua tables take on quite a few forms.
Arrays
One of the most common uses of the table is as an array.
An array is a collection of data stored in some organized manner in memory. That manner determines how the data is accessed later on.
Like a variable stores some data, arrays do as well. But unlike a variable, tables have the ability to store almost any number of elements.
Technically, the table consists of two different types of “arrays” but we’re getting ahead of ourselves. Let’s create a table/array.
local someList = {}
someList[1] = math.random()
someList[2] = math.random(10)
someList[3] = math.random(-10, 10)
print(someList[1], someList[2], someList[3], someList[4])
The first line constructs an empty table named ‘someList.’
Because tables already have a built-in array, there is not an additional step required to begin using it as an array. Square brackets index the array element.
In the example above, the first, second, and third elements of the array are assigned a random number.
If an index has not been assigned, it will return nil like the output shows for the 4th element when we attempt to index it.
The most basic type of array is some contiguous span of memory divided down in to smaller elements of identical size. This is called an ‘indexed array‘ or often just ‘array‘ because each element is indexed using integer values.
Lua arrays do not have a fixed or maximum size but are automatically resized behind-the-scenes as more elements are added.
Arrays can be initialized when they are constructed. In this manner, the indices start on index 1.
local someList = {math.random(), math.random(10), math.random(-10, 10)}
print(someList[1], someList[2], someList[3], someList[4])
You can also assign values to specific indices when the table is initialized or afterwards. As well as skip indices altogether.
local someList = {[3] = math.random(), [12] = math.random(10), [7] = math.random(-10, 10)}
someList[4] = math.random(-10, 10)
print(someList)
Because some indices were skipped, this is called a ‘sparse array‘ due to the “holes.”
One of Lua’s peculiarities is that by default, the array index starts at 1.
If you’re coming from other languages, you might be used to arrays starting at index 0. If this is your first language, most other languages start at index 0.
Index 1 is not strictly required, however
local someList = {[-1] = math.random(),
[0] = math.random(),
[1] = math.random(),
}
print(someList)
Lua arrays can be used to store almost anything, including other arrays or some combination.
local newPart = Instance.new("Part")
newPart.Parent = game.Workspace
local someList = {
{"Hello", "world!"},
{3.14, 42, 123},
newPart
}
print(someList)
This table contains a nested table/array in its first element, which itself contains two string elements.
The second element is another table—this one three deep.
The third element points to the new part that we just created.
(The output might be collapsed by default so you will have to expand it to view the contents.)
Getting Multiple Child Objects
Oftentimes you need a list of all children of an object. For instance, if you need a list of inventory items for a player.
Every class has a ‘GetChildren‘ method that returns an array of all immediate children of that object.
local children = game.Workspace:GetChildren()
print(children)
--[[ Output:{
[1] = Camera,
[2] = Baseplate,
[3] = Terrain,
[4] = SpawnLocation,
[5] = Part,
[6] = Script
}
]]
Note that these refer to the objects and are not just the string names of those objects
If the immediate children objects is not comprehensive enough, you can get every descendant of the object using the ‘GetDescendants‘ method.
local descendants = game.Workspace:GetDescendants()
print(descendants)
--[[ Output: {
[1] = Camera,
[2] = Baseplate,
[3] = Texture,
[4] = Terrain,
[5] = SpawnLocation,
[6] = Decal,
[7] = Part
}
]]