Lua programming/Tables

Tables are the only data structure in Lua, but they are more flexible than the data structures in many other languages. They are created using tables constructors, which are defined by two braces that may optionally contain values separated by commas or semicolons. The following example demonstrates an array (an ordered list of values) and demonstrates how an array's length can be obtained.

local array = {5, "text", {"more text", 463, "even more text"}, "more text"}
print(#array) --> 4 ; the # operator for strings can also be used for arrays, in which case it will return the number of values in the array
-- This example demonstrates how tables can be nested in other tables. Since tables themselves are values, tables can include other tables. Arrays of tables are called multi-dimensional arrays.

Tables may contain values of any type except nil. This is logical: nil represents the absence of a value. Inserting "the absence of a value" in a table wouldn't make sense. Values in tables may be separated either by commas or semicolons, and they may continue on many lines. It is common to use commas for single-line table constructors and semicolons for multi-line tables, but this is not necessary.

local array = {
        "text";
        {
                "more text, in a nested table";
                1432
        };
        true -- booleans can also be in tables
}

Tables are composed of fields, which are pairs of values, one of which is a index (also called a key) the other being the value that corresponds to that index. In arrays, the indices are always numerical values. In dictionaries, which are also called associative arrays or maps, the indices can be any value.

local dictionary = {
        "text";
        text = "more text";
        654;
        [8] = {} -- an empty table
        func = function() print("tables can even contain functions!") end;
        ["1213"] = 1213
}

As the example above illustrates, values can be added to a dictionary like they are in arrays with just the value (in which case the index will be a number), with an identifier and an equal sign prefixing the value (in which case the index will be the string that corresponds to the identifier) or with a value enclosed in parentheses and an equal sign prefixing the value (in which case the index is the value in parentheses). The latter is the most flexible way to make an index correspond to a value because it can be used with any value or expression.

It is possible to access a value in a table by putting the index the value corresponds to inside brackets, after an expression that evaluates to the table:

local dictionary = {number = 6}
print(dictionary["number"]) --> 6

If the index is a string which follows the criteria for Lua identifiers (it doesn't contain spaces, start with a number or contain anything else than numbers, letters and underscores), it can be accessed without brackets, by prefixing the string with a dot:

local dictionary = {["number"] = 6}
print(dictionary.number) --> 6

The two previous examples create an identical table and print the same value, but define and access the indices using different notations. It is also possible, in the case of tables that contain other tables to access a value that is inside the nested table by first indexing the first table to get the nested table, and then indexing the value inside of the nested table:

local nested_table = {
        [6] = {
                func = function() print("6") end
        }
}
nested_table[6].func() -- This will access the nested table, access the function that is inside it and then call that function, which will print the number 6.

Foreach loop

The chapter on statements described two types of loops: condition-controlled loops and count-controlled loops. In Lua, there is a third type of loop, the foreach loop. A foreach loop is a loop that allows the programmer to execute code for each field in a table. The example below demonstrates a foreach loop that traverses the items in an array of numbers and prints all the indices and the sum of the values that correspond to them with the number one:

local array = {5, 2, 6, 3, 6}
 
for index, value in next, array do
        print(index .. ": " .. value + 1)
end
-- Output:
-- 1: 6
-- 2: 3
-- 3: 7
-- 4: 4
-- 5: 7

The two loops in the following example will do the same thing as the loop in the previous example.

local array = {5, 2, 6, 3, 6}
 
for index, value in pairs(array) do
        print(index .. ": " .. value + 1)
end
 
for index, value in ipairs(array) do
        print(index .. ": " .. value + 1)
end

The method shown in the first example does the same thing as the first loop in the previous example. However, the last one (the one that uses the ipairs function) will only iterate up to the first integer key absent from the table, which means it will only iterate through numerical values that are in order as they are in an array. There are also two functions called table.foreach and table.foreachi. You might encounter them, but they should be avoided because they are deprecated. Deprecation is a status applied to a feature or practice to indicate that it has been removed or superseded and that it should be avoided. Using the foreach loop to traverse tables is therefore preferable to using these two functions.

↑Jump back a section

Unpacking tables

In Lua, a distinction is made between a tuple, a simple list of values, and a table, a data structure that maps indices to values. A function call to a function that returns many values evaluates to a tuple. A list of values in an assignment statement where many variables are assigned at once is also a tuple. The vararg expression, which is used in variadic functions, is also a tuple. Because a tuple is a list of values and therefore not a single value, it cannot be stored in a variable, although it can be stored in many variables. It is possible to convert a tuple into an array by putting the expression that evaluates to the tuple in a table constructor.

function return_tuple()
        return 5, 6 -- Because this function returns two values, a function call to it evaluates to a tuple.
end
 
local array = {return_tuple()} -- same as local array = {5, 6}
local a, b = return_tuple() -- same as local a, b = 5, 6
print(return_tuple()) -- same as print(5, 6)

It is possible to unpack an array (change it from a table to a tuple) by using the unpack function with the array as an argument:

local array = {7, 4, 2}
local a, b, c = unpack(array)
print(a, b, c) --> 7, 4, 2
↑Jump back a section

Methods

Because tables can contain functions and associate a name to these functions, they will often be used to create libraries. Lua also has syntactic sugar that can be used to create methods, functions that are used to manipulate an object, which will generally be represented by the table. This might be a bit hard to understand to someone who doesn't know about object-oriented programming, which is out of the scope of this book, so there's nothing wrong with not understanding the purpose of this. The two examples below do exactly the same thing:

local object = {}
 
function object.func(self, arg1, arg2)
        print(arg1, arg2)
end
 
object.func(object, 1, 2) --> 1, 2
local object = {}
 
function object:func(arg1, arg2)
        print(arg1, arg2)
end
 
object:func(1, 2) --> 1, 2

When calling a function that is in a table and that corresponds to a index that is a string, using a colon instead of a dot will add a hidden argument which is the table itself. Similarly, defining a function in a table using a colon instead of a dot will add a hidden self parameter in the parameter list. Usage of a colon to define the function doesn't mean a colon must also be used to call the function and vice-versa, because these are completely interchangeable.

Next Page: Algorithms | Previous Page: Functions

Home: Lua programming

↑Jump back a section
Last modified on 6 April 2013, at 17:43