Tables

Preface

Remarks

  • The examples on this page have not been made to run in Celestia but in the lua console. Things like the print statements are not the Celestia statements but the native lua equivalents. Change "print()" to celestia:print() and the examples will also run in Celestia.

Links:

Table print functions

The lua table type has no default function to print the contents of a table's elements. The lua print function wil print a table's internal ID, not it's contents. The examples on this page use the two functions below: print_array and print_dict.

Function: print_array

-- function: print_array

-- prints a table based on it's index, using the ipairs function

function print_array(a)

print(a)

print("array_length = " ..# a)

print("array_content = ")

for index, value in ipairs(a) do

print(index, value)

        end
end

Function: print_dict

-- function: print_dict
-- prints a table based on it's key/value pairs, using the pairs function
function print_dict(d)
    print(d)
    print("dict_length  = " ..# d)
    print("dict_content = ")
    for key, value in pairs(d) do
        print(key, value)
    end
end

General

Arrays and dictionaries

At first glance lua seems to support two different types of "lists": the array and the dictionary.

> -- the array
> array = { 10, 20, 30, 40 }
> print( "2 = " ..array[2] )

2 = 20

> -- the dictionary

> dict = { sun = "Sol", planet = "Earth", moon = "Moon" }

> print( "Planet's sun = " ..dict[ "sun" ] )
Planet's sun = Sol

There is however only 1 type of list in lua and that is the "table" type. This type is a dictionary by default. Arrays only appéar to be stored as arrays; in reality they are stored as dictionaries, whereby the index value is used as the key value. This is clearly shown when printing the "array" using the table type's key/value iterator "pairs()".

> for key, value in pairs(array) do

> print("Key = " ..key ..", value = " ..value)

> end
Key = 1,  value = 10
Key = 2,  value = 20

Key = 3, value = 30

Key = 4, value = 40

There are no real arrays; lua's syntax only allows you to approach a table as if it were an array or as if it were a dictionary. You can even use both syntaxes on one and the same table. Be careful with that though, since it can lead to unexpected results. A script like this for instance:

> list = { 10, 20, 30, 40 }              -- approach as an array

> list["sun"] = "Sol" -- approach as a dict

> list["planet"] = "Earth" -- approach as a dict

> print("Length = ",# list)
> print("Print as array:")
> for index, value in ipairs(list) do
>     print(index, value)
> end
> print("Print as dictionary:")
> for key, value in pairs(list) do
>     print(key, value)
> end

Leads to this result:

Length =     4
Print as array:
1      10
2      20
3      30
4      40
Print as dictionary:
1      10
2      20
3      30
4      40
planet Earth
sun    Sol

The example shows that in "mixed use":

    1. The length function does nót count the "dictionary part" of the table, only the "array part".
    2. The Ipairs() function only iterates the "array part", whereas pairs() iterates both parts.

Element values

Table element values can be of any type even that of a function:

> table = {}
> table[1] = 1
> table[2] = "one"
> table[3] = { 1, "1", "one"}
> table[4] = print_array
> print_array(table)

table: 000000000062DA20

array_length  = 4
array_content =
1    1
2    one

3 table: 000000000062E1F0

4 function: 0000000000618750

! Nil values

Lua has an odd way of dealing with nil values in tables. In the example below the third element of the table "list" has a value of nil as is confirmed by the print statement.

> list = { 4, 3, nil, 1 }
> print("index 3 = ", list[3])
index 3 = nil

The pairs() iterator function as used by "print_dict" ignores elements with a value equal to nil completely, as is shown in the example below, where the third element is missing completely in the printed list.

> print_dict(list)
table: 000000000062DA20
dict_length  = 4
dict_content =
1    4
2    3
4    1

The absence of element 3 in the list does not result from any odd behaviour by the print() funtion. The test below shows clearly that it results from the fact that the pairs() iterator does not return elements that have a value of nil.

> for key, value in pairs(list) do
>     if value == nil then
>   print(key, "nil")
>   else
>   print(key, value)
>   end
> end
1    4
2    3
4    1

The ipairs() iterator function as used by "print_array" is even worse with nil values. It considers an element with a nil value to be the end of the table and it simply stops iterating the table all together, as is shown below.

> list = { 4, 3, nil, 1 }
> print("index 3 = ",list[3])
index 3 = nil
> print_array(list)

table: 000000000062DA20

array_length  = 4
array_content =
1    4
2    3

This behaviour of lua is not a bug, but structural and by design! It's important to keep this in mind when creating scripts that rely on tables that máy contain nil values. Notice that in both cases the length function dóes return the correct length.

Arrays

The table type approached as if it were an array.

> array = {}
> array[1] = 1
> array[2] = 2
> array[3] = 3
> print_array(array)
table: 000000000062DA20
array_length  = 3
array_content =
1    1
2    2
3    3

An alternative syntax for defining an array is:

> array = { 1, 2, 3 }
> print_array(array)
table: 000000000062DA20
array_length  = 3
array_content =
1    1
2    2
3    3

! Notice that indexing starts at 1 not at 0 (zero). It is not that one can't assign a value to index 0, but it will not be returned by the array iterator "ipairs()". To show this, the example below adds a value to index [0] of the array from the previous example and then prints the result.

> array[0] = 999
> print_array(array)
table: 000000000062DA20
array_length  = 3
array_content =
1    1
2    2
3    3
> print("index_zero = " ..array[0])
index_zero = 999

There is no append function with that name; to append a value to (the end of) a table, use the insert function without a position parameter

> array = {}
> table.insert(array, 1)                     -- insert used as "append"
> table.insert(array, 2)
> table.insert(array, 3)
> print_array(array)
table: 000000000062DA20
array_length  = 3
array_content =
1    1
2    2
3    3
> table.insert(array, 2, 99)                 -- insert used as "insert"
> table.insert(array, 4, 99)
> print_array(array)
table: 000000000062DA20
array_length  = 5
array_content =
1    1
2    99
3    2
4    99
5    3
> table.remove(array, 4)
> table.remove(array, 2)
> print_array(array)
table: 000000000062DA20
array_length  = 3
array_content =
1    1
2    2
3    3

Dictionaries

The table type approached as if it were a dictionary.

> dict = {}
> dict["sun"]    = "Sol"

> dict["planet"] = "Earth"

> dict["moon"]   = "Moon"
> print_dict(dict)
table: 000000000062DA20
dict_length  = 0
dict_content =
planet   Earth
sun      Sol
moon     Moon

! Notice:

    • That the length is printed as being zero. This is because by design the lua length function can not be used to obtain the length of a dictionary. For dictionaries the function will allways return zero.
    • How the dictionary elements are printed in arbitrary order; it is not in the original (input) order, nor in key value or even value order. This is because the dictionary iterator "pairs()" returns the elements in this arbitrary order. So apparently the table type is an unsorted dictionary.

An alternative syntax for defining a dictionary is:

> dict = { sun = "Sol", planet = "Earth", moon = "Moon" }
> print_dict(dict)
table: 000000000062DA20
dict_length  = 0
dict_content =
planet   Earth
sun      Sol
moon     Moon

Notice that the key values in the example are written withóut quotes. This is a requirement for this variant; enclosing a key value in quotes leads to a syntax error. In this syntax variant the key values múst be valid lua identifiers; i.e.:

    • any string of letters, digits, and underscores, not beginning with a digit

There is also this third variant:

> dict = {}
> dict.sun    = "Sol"

> dict.planet = "Earth"

> dict.moon   = "Moon"
> print_dict(dict)
table: 000000000062DA20
dict_length  = 0
dict_content =
planet   Earth
sun      Sol
moon     Moon

This variant is more a syntactic sugar to give lua a more "object oriented" look & feel than realy a different variant. Because of the notation also in this variant the key values múst be valid lua identifiers.