Tables: Difference between revisions

From Legacy Roblox Wiki
Jump to navigationJump to search
>Mindraker
This needs to be put into noobspeak
m Text replacement - "<SyntaxHighlight code="lua">" to "<syntaxhighlight lang="lua">"
 
(63 intermediate revisions by 13 users not shown)
Line 1: Line 1:
__TOC__


== Introduction ==
A {{type|table}} is a data type in Lua that is useful to store multiple values, including {{type|number|numbers}}, {{type|string|strings}}, {{type|function|functions}}, more {{type|table|tables}}, and much more. It is called a table because it acts like a grid with two columns:


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". -->
{| class="wikitable"
! Key  !!Value
|-
||&nbsp;||&nbsp;
|}


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 {}:
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 ({{type|number|numbers}}, {{type|string|strings}}, {{type|instance=Part|Parts}} etc., and even other tables) except {{nil}}. Lua tables do not have to use either {{type|number|numbers}}, {{type|string|strings}} or {{type|table|tables}} as keys. Any combination of key types can be used.


<pre>
Another way to describe it is that by inputting the key, you receive the value.  
    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:
The # operator will return the amount of keys that are {{type|number|numbers}}.


<pre>
== Arrays ==
    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.
Each table may store values with different types of indices and it grows as it needs to accommodate new entries:
 
<pre>
    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.
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>
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.
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>
An array is a list of values, stored in order. It is a table where the keys are sequential integers starting at 1, e.g. 1, 2, 3, 4. Arrays are useful for creating lists of things, such as a list of players with special permissions.
    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 ==
===Creating arrays===


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.
Arrays are created with a pair of braces ({ and }, containing the values to store in the array separated by commas (,) or semicolons (;). The values can be of any type
<syntaxhighlight lang="lua">
local myArray = {"A string", 3.14159, Workspace.Part}
local myEmptyArray = {}
</syntaxhighlight>


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
=== Reading from and writing to arrays ===


<pre>
To read from an array, add a pair of brackets ([ and ]) after the array, and put the number of the element you want inside it. The first element in the array is number 1
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
<syntaxhighlight lang="lua">
            "Thursday", "Friday", "Saturday"}
print(myArray[1])              --> A string
</pre>
print(myArray[2])              --> 3.14159
print(myArray[3]:GetFullName()) --> Workspace.Part


will initialize days[1] with the string "Sunday" (the first element has always index 1, not 0), days[2] with "Monday", and so on:
myArray[2] = "Pi"
print(myArray[2])              --> Pi
</syntaxhighlight>


<pre>
===More information===
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
print(days[4])
Will result in:
Wednesday
</pre>


For those that really want their arrays starting at 0, it is not difficult to write the following:  
You can get the length of the array with the # operator:
<syntaxhighlight lang="lua">
print(#myArray)      --> 3
print(#myEmptyArray ) --> 0
</syntaxhighlight>


    days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
Lua's [[Function_Dump/Table_Manipulation|table manipulation]] functions allow you to easily do things such as add and remove values from an array.
            "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.
== Dictionaries ==
You can always put a comma after the last entry. These trailing commas are optional, but are always valid:
Dictionaries are an extension of arrays. While an array stores an ordered list of items, a dictionary stores a set of key/value pairs. For example, in a real dictionary, the "keys" are the words, and the "values" the definition.


    a = {[1]="red", [2]="green", [3]="blue",}
=== Creating a dictionary ===
 
Once again, dictionaries are created with braces
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.
<syntaxhighlight lang="lua">
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:
local myDictionary = {
 
["Roblox"] = "A massively multiplayer online game",
    {x=10, y=45; "one", "two", "three"}
["Wiki"] = "A Web site developed collaboratively by a community of users",
 
["Lua"] = "A lightweight multi-paradigm programming language"
== Arrays ==
}
</syntaxhighlight>


<!-- 11.1 -->
Like arrays, dictionaries are not restricted to strings. Both the keys and the values can be of any type.


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
<syntaxhighlight lang="lua">
local playerScores = {
[game.Players.Telamon] = "Over 9000!",
[game.Players.ROBLOX] = 1337,
[game.Players.Sorcus] = Enum.DialogTone.Enemy
}
</syntaxhighlight>


    a = {}    -- new array
====Shorthand for string keys====
    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.
If a key in a dictionary is a string, and a valid Lua identifier (that is, it can be used as [[Variables#Names|the name of a variable]]), the quotes and brackets can be omitted:
You can start an array at index 0, 1, or any other value:  


    -- creates an array with indices from -5 to 5
<syntaxhighlight lang="lua">
    a = {}
local myDictionary = {
    for i=-5, 5 do
Roblox = "A massively multiplayer online game",
      a[i] = 0
Wiki = "A Web site developed collaboratively by a community of users",
    end
Lua = "A lightweight multi-paradigm programming language"
}
</syntaxhighlight>


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.
===Indexing a dictionary ===
We can use constructors to create and initialize arrays in a single expression:


    squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}
Getting values into and out of a table is called ''indexing''. An ''index'' in a table is like a row in the table model above. To index something in a table, you first need the key for the index you want to get or change the value in. You put the key in square brackets ('''[]''') after the table that that is to be looked in. For example, to get or change the index with the key 1 in the table myTable, we write myTable[1]. You can then use this exactly like a [[variable]] or value: it can be used, or set to a different value. For example, to store the string "A value" in myTable in the row with the key 1, we would write:


Such constructors can be as large as you need (well, up to a few million elements).
<syntaxhighlight lang="lua">
myTable = {}
myTable[1] = "A value"
</syntaxhighlight>


== Matrices and Multi-Dimensional Arrays ==
myTable[1] can now be used in other places. For example, the print function:


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:
<syntaxhighlight lang="lua">print(myTable[1]) --> A value</syntaxhighlight>


<pre>
If there is already an index in the table with the key that is being set, the old value will be replaced with the new one:
    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
<syntaxhighlight lang="lua">
      for j=1,M do
myTable[1] = "A new value"
print(myTable[1]) --> A new value (as apposed to "A value")
</syntaxhighlight>


in the previous example to  
If there isn't a row with the key we're using when we try to ''get'' a value, it will return {{nil}}:
      for j=1,i do


With that code, the triangular matrix uses only half the memory of the original one.
<syntaxhighlight lang="lua">print(myTable[2]) --> nil</syntaxhighlight>
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>
== Iteration through tables ==
    mt = {}          -- create the matrix
    for i=1,N do
      for j=1,M do
        mt[i*M + j] = 0
      end
    end
</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.  
''Iteration'' is the repetition of an action. In this case, you are iterating through the values in a table by taking each value and doing something with it. For-loops (and sometimes while-loops) are used to iterate with tables. You can use the [[Function_Dump/Core_Functions#pairs_.28t.29|pairs]] (or [[Function_Dump/Core_Functions#ipairs_.28t.29|ipairs]] if you only want to iterate over the number keys) function to write a for-loop that goes through every value in a table with the value's key.


<syntaxhighlight lang="lua">
for key, value in pairs(myOtherTable) do
print(key, "=", value)
end


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.
--[[
Output:
1 = A value
A string key = Another value
2 = 5
]]
</syntaxhighlight>


== Pass by reference ==


== See Also ==
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'' (or pointer) to it. This means that when more than one variable is set to a table, the variables ''do not'' each have a copy of the table, they refer to the same table, so any changes will be noticed by ''both'' variables:


[http://www.lua.org/pil/2.5.html 2.5 - Tables]
<syntaxhighlight lang="lua">
var1 = {}
var2 = var1
var2["key"] = "value"
print(var1["key"]) -- prints "value" because var2 had pointed to var1's value (the table)
</syntaxhighlight>


[http://www.lua.org/pil/2.5.html 3.6 - Table Constructors]
== See also ==


[http://www.lua.org/pil/11.2.html 11.2 - Matrices and Multi-Dimensional Arrays]
* [[Metatables]]
* From Programming in Lua:
** [http://www.lua.org/pil/2.5.html 2.5 - Tables]
** [http://www.lua.org/pil/2.5.html 3.6 - Table Constructors]
** [http://www.lua.org/pil/11.2.html 11.2 - Matrices and Multi-Dimensional Arrays]
* [http://lua-users.org/wiki/TablesTutorial Tables Tutorial] on Lua Users wiki
* Using Tables to create data structures:
** [[Linked lists]]
** [[Stack]]
[[Category:Data types]]

Latest revision as of 06:18, 27 April 2023

A table is a data type in Lua that is useful to store multiple values, including numbers, strings, functions, more tables, and much more. 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, Parts etc., and even other tables) except nil. Lua tables do not have to use either numbers, strings or tables as keys. Any combination of key types can be used.

Another way to describe it is that by inputting the key, you receive the value.

The # operator will return the amount of keys that are numbers.

Arrays

An array is a list of values, stored in order. It is a table where the keys are sequential integers starting at 1, e.g. 1, 2, 3, 4. Arrays are useful for creating lists of things, such as a list of players with special permissions.

Creating arrays

Arrays are created with a pair of braces ({ and }, containing the values to store in the array separated by commas (,) or semicolons (;). The values can be of any type

local myArray = {"A string", 3.14159, Workspace.Part}
local myEmptyArray = {}

Reading from and writing to arrays

To read from an array, add a pair of brackets ([ and ]) after the array, and put the number of the element you want inside it. The first element in the array is number 1

print(myArray[1])               --> A string
print(myArray[2])               --> 3.14159
print(myArray[3]:GetFullName()) --> Workspace.Part

myArray[2] = "Pi"
print(myArray[2])               --> Pi

More information

You can get the length of the array with the # operator:

print(#myArray)       --> 3
print(#myEmptyArray ) --> 0

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

Dictionaries

Dictionaries are an extension of arrays. While an array stores an ordered list of items, a dictionary stores a set of key/value pairs. For example, in a real dictionary, the "keys" are the words, and the "values" the definition.

Creating a dictionary

Once again, dictionaries are created with braces

local myDictionary = {
	["Roblox"] = "A massively multiplayer online game",
	["Wiki"] = "A Web site developed collaboratively by a community of users",
	["Lua"] = "A lightweight multi-paradigm programming language"
}

Like arrays, dictionaries are not restricted to strings. Both the keys and the values can be of any type.

local playerScores = {
	[game.Players.Telamon] = "Over 9000!",  
	[game.Players.ROBLOX] = 1337,
	[game.Players.Sorcus] = Enum.DialogTone.Enemy
}

Shorthand for string keys

If a key in a dictionary is a string, and a valid Lua identifier (that is, it can be used as the name of a variable), the quotes and brackets can be omitted:

local myDictionary = {
	Roblox = "A massively multiplayer online game",
	Wiki = "A Web site developed collaboratively by a community of users",
	Lua = "A lightweight multi-paradigm programming language"
}

Indexing a dictionary

Getting values into and out of a table is called indexing. An index in a table is like a row in the table model above. To index something in a table, you first need the key for the index you want to get or change the value in. You put the key in square brackets ([]) after the table that that is to be looked in. For example, to get or change the index with the key 1 in the table myTable, we write myTable[1]. You can then use this exactly like a variable or value: it can be used, or set to a different value. For example, to store the string "A value" in myTable in the row with the key 1, we would write:

myTable = {}
myTable[1] = "A value"

myTable[1] can now be used in other places. For example, the print function:

print(myTable[1]) --> A value

If there is already an index in the table with the key that is being set, the old value will be replaced with the new one:

myTable[1] = "A new value"
print(myTable[1]) --> A new value (as apposed to "A value")

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

print(myTable[2]) --> nil

Iteration through tables

Iteration is the repetition of an action. In this case, you are iterating through the values in a table by taking each value and doing something with it. For-loops (and sometimes while-loops) are used to iterate with tables. You can use the pairs (or ipairs if you only want to iterate over the number keys) function to write a for-loop that goes through every value in a table with the value's key.

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

--[[
Output:
1 = A value
A string key = Another value
2 = 5
]]

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 (or pointer) to it. This means that when more than one variable is set to a table, the variables do not 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" because var2 had pointed to var1's value (the table)

See also