Tables: Difference between revisions

From Legacy Roblox Wiki
Jump to navigationJump to search
>Blocco
No edit summary
>Sncplay42
Replaced PIL copypasta with new tutorial
Line 1: Line 1:
__TOC__
A '''table''' is a useful way to store multiple values in one value. It is called a table because it acts like a grid with two columns:


== Introduction ==
{| border="1"
! Key  !!Value
|-
|| || 
|}


The table type implements associative arrays. An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil. Moreover, tables have no fixed size; you can add as many elements as you want to a table dynamically. Tables are the main (in fact, the only) data structuring mechanism in Lua, and a powerful one. We use tables to represent ordinary arrays, symbol tables, sets, records, queues, and other data structures, in a simple, uniform, and efficient way. Lua uses tables to represent packages as well.  <!-- When we write io.read, we mean "the read entry from the io package". For Lua, that means "index the table io using the string "read" as the key". -->
The ''key'' column is used to find a row in the table, and the ''value'' is the value that is stored in that row. Both the key and value can be any Lua value (numbers, strings, the values of variables, [[Part]]s etc., even other tables!) except [[nil]].


Tables in Lua are neither values nor variables; they are objects. If you are familiar with arrays in Java or Scheme, then you have a fair idea of what we mean. However, if your idea of an array comes from C or Pascal, you have to open your mind a bit. You may think of a table as a dynamically allocated object; your program only manipulates references (or pointers) to them. There are no hidden copies or creation of new tables behind the scenes. Moreover, you do not have to declare a table in Lua; in fact, there is no way to declare one. You create tables by means of a constructor expression, which in its simplest form is written as {}:
__TOC__


<pre>
==Creating a table==
    a = {}    -- create a table and store its reference in `a'
    k = "x"
    a[k] = 10        -- new entry, with key="x" and value=10
    a[20] = "great"  -- new entry, with key=20 and value="great"
    print(a["x"])    --> this will print 10
    k = 20
    print(a[k])      --> this will print "great"
    a["x"] = a["x"] + 1    -- increments entry "x"
    print(a["x"])    --> this will print 11
</pre>


A table is always anonymous. There is no fixed relationship between a variable that holds a table and the table itself:  
To create a table we use a pair of curly brackets ('''{}'''). We can then store the table in a [[variable]]:


<pre>
<pre>myTable = {}</pre>
    a = {}
    a["x"] = 10
    b = a      -- `b' refers to the same table as `a'
    print(b["x"])  --> This will print 10
    b["x"] = 20
    print(a["x"])  --> This will print 20
    a = nil    -- now only `b' still refers to the table
    b = nil    -- now there are no references left to the table
</pre>


When a program has no references to a table left, Lua memory management will eventually delete the table and reuse its memory.
==Indexing a table==
Each table may store values with different types of indices and it grows as it needs to accommodate new entries:


<pre>
Getting values into and out of a table is called ''indexing''. First we need the key for the row we want to get or change the value in. We write this in square brackets ('''[]''') after the table is in. For example, to get or change the row with the key 1 in the table <code>myTable</code>, we would write <code>myTable[1]</code>. We can then use this exactly like a [[variable]]: we can use its value in other places, or we can set it. For example, to store the string "A value" in <code>myTable</code> in the row with the key 1, we would write:
    a = {}    -- empty table
    -- create 1000 new entries
    for i=1,1000 do a[i] = i*2 end
    print(a[9])   --> This will print 18
    a["x"] = 10
    print(a["x"])  --> This will print 10
    print(a["y"])  --> This will print nil
</pre>


Notice the last line: Like global variables, table fields evaluate to nil if they are not initialized. Also like global variables, you can assign nil to a table field to delete it. That is not a coincidence: Lua stores global variables in ordinary tables.
<pre>myTable[1] = "A value"</pre>
To represent records, you use the field name as an index. Lua supports this representation by providing a.name as syntactic sugar for a["name"]. So, we could write the previous example in a cleanlier manner as


<pre>
Now we can use <code>myTable[1]</code> in other places:
a = {}
for i=1,1000 do a[i] = i*2 end
print(a[9])
a.x = 10                    -- same as a["x"] = 10
print(a.x)                  -- same as print(a["x"])
print(a.y)                  -- same as print(a["y"])
</pre>


For Lua, the two forms are equivalent and can be intermixed freely; but for a human reader, each form may signal a different intention.
<pre>print(myTable[1]) -- prints: A value</pre>
A common mistake for beginners is to confuse a.x with a[x]. The first form represents a["x"], that is, a table indexed by the string "x". The second form is a table indexed by the value of the variable x. See the difference:


<pre>
If there is already a row in the table with the key we're trying to set, the old one will be changed:
    a = {}
    x = "y"
    a[x] = 10                -- put 10 in field "y"
    print(a[x])  --> 10      -- value of field "y"
    print(a.x)    --> nil    -- value of field "x" (undefined)
    print(a.y)    --> 10      -- value of field "y"
</pre>


== Table Constructors ==
<pre>myTable[1] = "A new value"
print(myTable[1]) -- prints: A new value</pre>


Table constructors are expressions that create and initialize tables. They are a distinctive feature of Lua and one of its most useful and versatile mechanisms.
If there isn't a row with the key we're using when we try to ''get'' a value, we will get [[nil]]:


The simplest constructor is the empty constructor, {}, which creates an empty table.  Constructors also initialize arrays (called also sequences or lists). For instance, the statement
<pre>print(myTable[2]) -- prints: nil</pre>


<pre>
== More on creating tables ==
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
</pre>


will initialize days[1] with the string "Sunday" (the first element has always index 1, not 0), days[2] with "Monday", and so on:
We can add keys to the table while we are creating a table in a very similar way to indexing. Inside the curly brackets, we can put lines that are very similar to indexing, but without the name of the table, and separated by commas.


<pre>
<pre>
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
myOtherTable = {
            "Thursday", "Friday", "Saturday"}
    [1] = "A value",
print(days[4])
    ["A string key"] = "Another value",
Will result in:
    [2] = 5
Wednesday
}
print(myOtherTable[1], myOtherTable["A string key"], myOtherTable[2]) -- prints: A value Another value 5
</pre>
</pre>


For those that really want their arrays starting at 0, it is not difficult to write the following:
''The commas are important!'' If they are not there, Lua will give an error message saying it expects the "}".


    days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
== Arrays ==
            "Thursday", "Friday", "Saturday"}


Now, the first value, "Sunday", is at index 0. That zero does not affect the other fields, but "Monday" naturally goes to index 1, because it is the first list value in the constructor; the other values follow it. Despite this facility, I do not recommend the use of arrays starting at 0 in Lua. Remember that most functions assume that arrays start at index 1, and therefore will not handle such arrays correctly.
An array, or list, is a table were all the keys are whole numbers (e.g. 1, 2, 3, 4...). This is very useful for creating lists of things, such as a list of people who can use a tool.
You can always put a comma after the last entry. These trailing commas are optional, but are always valid:


    a = {[1]="red", [2]="green", [3]="blue",}
When we are creating arrays, we can miss out the <code>["key"] =</code> part, and just write the values separated by commas, and Lua will automatically use the numbers 1, 2, 3, 4, 5... as the keys:


Such flexibility makes it easier to write programs that generate Lua tables, because they do not need to handle the last element as a special case.
<pre>myArray = {"First value", "Second value", "Third value"}
Finally, you can always use a semicolon instead of a comma in a constructor. We usually reserve semicolons to delimit different sections in a constructor, for instance to separate its list part from its record part:
print(myArray[1]) -- prints: First value
 
print(myArray[2]) -- prints: Second value
    {x=10, y=45; "one", "two", "three"}
print(myArray[3]) -- prints: Third value
</pre>


== Arrays ==
We can get the number of values in an array (but ''not'' a normal table, only number keys are counted) by using the '''#''' operator:


<!-- 11.1 -->
<pre>print(#myArray) -- prints: 3</pre>


We implement arrays in Lua simply by indexing tables with integers. Therefore, arrays do not have a fixed size, but grow as we need. Usually, when we initialize the array we define its size indirectly. For instance, after the following code
Lua's [[Function_Dump/Table_Manipulation|table manipulation]] functions allow you to easily do things such as add and remove values from an array.


    a = {}    -- new array
'''Note''': Normally, [[nil]] should not be used as a value in an array. # and Lua's table manipulation functions use nil to tell where an array ends. Putting them in the middle of your table may make Lua think the array ends there.
    for i=1, 1000 do
      a[i] = 0
    end


any attempt to access a field outside the range 1-1000 will return nil, instead of zero.
== Loops through tables ==
You can start an array at index 0, 1, or any other value:


    -- creates an array with indices from -5 to 5
We can use the [[Function_Dump/Core_Functions#pairs_.28t.29|pairs]] and [[Function_Dump/Core_Functions#ipairs_.28t.29|ipairs]] functions to write a loop that goes through every value in an array:
    a = {}
    for i=-5, 5 do
      a[i] = 0
    end


However, it is customary in Lua to start arrays with index 1. The Lua libraries adhere to this convention; so, if your arrays also start with 1, you will be able to use their functions directly.
<pre>for key, value in pairs(myOtherTable) do
We can use constructors to create and initialize arrays in a single expression:
    print(key, "=", value)
end


    squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}
Outputs:
1 = A value
A string key = Another value
2 = 5</pre>


Such constructors can be as large as you need (well, up to a few million elements).
<pre>for key, value in ipairs(myArray) do
    print(key, "=", value)
end


== Matrices and Multi-Dimensional Arrays ==
Outputs:
 
1 = First value
There are two main ways to represent matrices in Lua. The first one is to use an array of arrays, that is, a table wherein each element is another table. For instance, you can create a matrix of zeros with dimensions N by M with the following code:  
2 = Second value
 
3 = Third value</pre>
<pre>
    mt = {}          -- create the matrix
    for i=1,N do
      mt[i] = {}    -- create a new row
      for j=1,M do
        mt[i][j] = 0
      end
    end
</pre>


Because tables are objects in Lua, you have to create each row explicitly to create a matrix. On the one hand, this is certainly more verbose than simply declaring a matrix, as you do in C or Pascal. On the other hand, that gives you more flexibility. For instance, you can create a triangular matrix changing the line
The difference between pairs and ipairs is that ipairs is designed for arrays - it only goes through the keys 1, 2, 3... until it finds a nil value. pairs goes through all the keys, but might not go through them in a set order.
      for j=1,M do


in the previous example to
== Pass by reference ==
      for j=1,i do


With that code, the triangular matrix uses only half the memory of the original one.
An important thing to understand when setting more than one variable to the same table is that tables are ''passed by reference''. This means that the variable doesn't directly contain the table itself, but that it holds a ''reference'' to it. This means that when more than one variable is set to a table, the variables ''don't'' each have a copy of the table, they refer to the same table, so any changes will be noticed by ''both'' variables:
The second way to represent a matrix in Lua is by composing the two indices into a single one. If the two indices are integers, you can multiply the first one by a constant and then add the second index. With this approach, the following code would create our matrix of zeros with dimensions N by M:  


<pre>
<pre>var1 = {}
    mt = {}         -- create the matrix
var2 = var1
    for i=1,N do
var2["key"] = "value"
      for j=1,M do
print(var1["key"]) -- prints "value"!
        mt[i*M + j] = 0
      end
    end
</pre>
</pre>


If the indices are strings, you can create a single index concatenating both indices with a character in between to separate them. For instance, you can index a matrix m with string indices s and t with the code m[s..':'..t], provided that both s and t do not contain colons (otherwise, pairs like ("a:", "b") and ("a", ":b") would collapse into a single index "a::b"). When in doubt, you can use a control character like `\0´ to separate the indices.
== See Also ==


 
[[Metatables]]
Quite often, applications use a sparse matrix, a matrix wherein most elements are 0 or nil. For instance, you can represent a graph by its adjacency matrix, which has the value x in position m,n only when the nodes m and n are connected with cost x; when those nodes are not connected, the value in position m,n is nil. To represent a graph with ten thousand nodes, where each node has about five neighbors, you will need a matrix with a hundred million entries (a square matrix with 10,000 columns and 10,000 rows), but approximately only fifty thousand of them will not be nil (five non-nil columns for each row, corresponding to the five neighbors of each node). Many books on data structures discuss at length how to implement such sparse matrices without wasting 400 MB of memory, but you do not need those techniques when programming in Lua. Because arrays are represented by tables, they are naturally sparse. With our first representation (tables of tables), you will need ten thousand tables, each one with about five elements, with a grand total of fifty thousand entries. With the second representation, you will have a single table, with fifty thousand entries in it. Whatever the representation, you only need space for the non-nil elements.
 
 
== See Also ==


[http://www.lua.org/pil/2.5.html 2.5 - Tables]
[http://www.lua.org/pil/2.5.html 2.5 - Tables]

Revision as of 20:52, 11 November 2010

A table is a useful way to store multiple values in one value. It is called a table because it acts like a grid with two columns:

Key Value
   

The key column is used to find a row in the table, and the value is the value that is stored in that row. Both the key and value can be any Lua value (numbers, strings, the values of variables, Parts etc., even other tables!) except nil.

Creating a table

To create a table we use a pair of curly brackets ({}). We can then store the table in a variable:

myTable = {}

Indexing a table

Getting values into and out of a table is called indexing. First we need the key for the row we want to get or change the value in. We write this in square brackets ([]) after the table is in. For example, to get or change the row with the key 1 in the table myTable, we would write myTable[1]. We can then use this exactly like a variable: we can use its value in other places, or we can set it. For example, to store the string "A value" in myTable in the row with the key 1, we would write:

myTable[1] = "A value"

Now we can use myTable[1] in other places:

print(myTable[1]) -- prints: A value

If there is already a row in the table with the key we're trying to set, the old one will be changed:

myTable[1] = "A new value"
print(myTable[1]) -- prints: A new value

If there isn't a row with the key we're using when we try to get a value, we will get nil:

print(myTable[2]) -- prints: nil

More on creating tables

We can add keys to the table while we are creating a table in a very similar way to indexing. Inside the curly brackets, we can put lines that are very similar to indexing, but without the name of the table, and separated by commas.

myOtherTable = {
    [1] = "A value",
    ["A string key"] = "Another value",
    [2] = 5
}
print(myOtherTable[1], myOtherTable["A string key"], myOtherTable[2]) -- prints: A value Another value 5

The commas are important! If they are not there, Lua will give an error message saying it expects the "}".

Arrays

An array, or list, is a table were all the keys are whole numbers (e.g. 1, 2, 3, 4...). This is very useful for creating lists of things, such as a list of people who can use a tool.

When we are creating arrays, we can miss out the ["key"] = part, and just write the values separated by commas, and Lua will automatically use the numbers 1, 2, 3, 4, 5... as the keys:

myArray = {"First value", "Second value", "Third value"}
print(myArray[1]) -- prints: First value
print(myArray[2]) -- prints: Second value
print(myArray[3]) -- prints: Third value

We can get the number of values in an array (but not a normal table, only number keys are counted) by using the # operator:

print(#myArray) -- prints: 3

Lua's table manipulation functions allow you to easily do things such as add and remove values from an array.

Note: Normally, nil should not be used as a value in an array. # and Lua's table manipulation functions use nil to tell where an array ends. Putting them in the middle of your table may make Lua think the array ends there.

Loops through tables

We can use the pairs and ipairs functions to write a loop that goes through every value in an array:

for key, value in pairs(myOtherTable) do
    print(key, "=", value)
end

Outputs:
1 = A value
A string key = Another value
2 = 5
for key, value in ipairs(myArray) do
    print(key, "=", value)
end

Outputs:
1 = First value
2 = Second value
3 = Third value

The difference between pairs and ipairs is that ipairs is designed for arrays - it only goes through the keys 1, 2, 3... until it finds a nil value. pairs goes through all the keys, but might not go through them in a set order.

Pass by reference

An important thing to understand when setting more than one variable to the same table is that tables are passed by reference. This means that the variable doesn't directly contain the table itself, but that it holds a reference to it. This means that when more than one variable is set to a table, the variables don't each have a copy of the table, they refer to the same table, so any changes will be noticed by both variables:

var1 = {}
var2 = var1
var2["key"] = "value"
print(var1["key"]) -- prints "value"!

See Also

Metatables

2.5 - Tables

3.6 - Table Constructors

11.2 - Matrices and Multi-Dimensional Arrays