If I were a carpenter... would you buy my tables?
I know, I should not quit my day job to be a songwriter. However having said that, it is not that bad either that I cannot have some new *artistes* buy my lyrics and make some rap spelled with a big C for Carpenter in the front, songs. Anyways, this is not about song and dance, nor about how to make your own carpentry home projects, we Aussies have Bunnings and I guess the Americans have Lowes and I do not know what the British and other have, but you get the idea. This is about creating arrays and tables in Lua as requested by one particular reader of these forums.
So, Darkconsoles, I am taking your request for tables and we shall try to see what tables are and how do we work and manipulate them.
In Lua, practically every object, other than primitives is a Table, note, a Table, not an array. Primitives are not object. So, numbers, boolean, and strings are primitives, where as functions, tables are all tables.
Tables can hold other tables, they can also hold primitives and functions.
Here are some fundamental differences between an array and a table
Array
An array has the first element as element #1, e.g. myArray[1] = "First Element"
An array cannot have named elements, e.g. myArray["next"] = "next" --This is not valid for an array
An array returns the length of the array via the #myArray function
Table
There is not such thing as a first element, as a table is more like a dictionary object or a KeyValuePair object.
The Table can have any elements, numbered or named
The table does not return anything for the #myTable as this # works only with Arrays or Strings
Yes, An array or a table can hold another table or array as an element, which is how one can achieve this multi-dimensionality
one can also create an array or table while declaring it, as
or a table as
Multi-dimension arrays can be declared using the same method
Now that we know the basics of an array and a table, let us look at some
First let us understand that tables are areas in memory that hold our data, so when we use the assignment operator " = " what we are doing is basically making the new variable also point to the same memory space.
To explain in detail,
You will notice that the values work as expected, but if we use this code
You will see that the output is not what one would have expected, it should have printed "Two", but it prints "Due". So this helps us understand one very important thing, which was mentioned earlier, each table is nothing but a pointer to a memory location. So when we assign local test = myArray[2] it points to the memory location holding the table data. In general this is one gotcha, that a lot of developers get trapped into, this will not create a copy of the array/table. To *Duplicate* the table data, we cannot just assign the variable to the data.
So what do we do now?
Lua has some functions in-built to work with tables, these are
To make a copy of this array/table, there are a couple of ways to manage it, one of them is to create a new table and populate the elements in it.
The other is to use the built-in function table.copy, the only issue with this function is that it does what is called a "Shallow Copy", it copies the items from an array (as defined earlier) so if we have a table, it will not work. The strange thing with Lua tables is that there is no certain way to find out if a table is a table or an array. This creates a problem as to what function to use, as there are two functions to iterate though each item in the table/array, ipairs and pairs.
ipairs iterates over each numeric index of the array, returning the index number and the element, if the element is another table, then the table is returned instead of the primitive.
pairs on the other hand works with the tables (key-value-pairs) and return the key and the value.
Let us also look at how to get the length of an array, the only way to actually get the array length is by counting the elements in the array. A missing element returns nil, so most functions stop counting once it finds a nil as in (with the above data)
Please do feel free to make comments in the comments below, after all it will be you that will help drive these tutorials.
Image src : Google Desk
So, Darkconsoles, I am taking your request for tables and we shall try to see what tables are and how do we work and manipulate them.
So first things first, what is a table.
In lua, Tables, Arrays are kind of used interchangeably, however they are *not* interchangeable, they are two distinct types each with it's own peculiaritiesIn Lua, practically every object, other than primitives is a Table, note, a Table, not an array. Primitives are not object. So, numbers, boolean, and strings are primitives, where as functions, tables are all tables.
Tables can hold other tables, they can also hold primitives and functions.
So how do we create a table,
local myTable = {}
How different is that from an array?
Yes, an array is also declared using the same method.Here are some fundamental differences between an array and a table
Array
An array has the first element as element #1, e.g. myArray[1] = "First Element"
An array cannot have named elements, e.g. myArray["next"] = "next" --This is not valid for an array
An array returns the length of the array via the #myArray function
Table
There is not such thing as a first element, as a table is more like a dictionary object or a KeyValuePair object.
The Table can have any elements, numbered or named
The table does not return anything for the #myTable as this # works only with Arrays or Strings
Multidimensionality
Can we have multi-dimension arrays or tables?Yes, An array or a table can hold another table or array as an element, which is how one can achieve this multi-dimensionality
local myArray = {} myArray [1] = "Array 1" myArray[2] = {} myArray[2][1] = "Item 1" myArray[2][2] = "Item 2"
one can also create an array or table while declaring it, as
local myArray = {"Array Item 1", "Array Item 2", "Array Item 3"} -- this will create an array with three items
or a table as
local myTable = {item1 = "Table Item 1", item2 = "Table Item 2", item3 = "Array Item 3"} -- this will create a Table with three items referred to as myTable.item1, myTable.item2, myTable.item3
Multi-dimension arrays can be declared using the same method
local myArray = { "Array Item 1", { "Item 1", "Item 2", "Item 3", "Item 4", }, "Array Item 3" } -- this will create an array with three items, where item 2 is a multi-dimension array having 4 itemsWith knowledge of this, you can see that one can create not only a 2 dimensional array / table, but a real multi-dimensional data set. However the only problem is that you have to ensure that there are elements, which means that you can definitely get an item for myArray[2][3], but a nil for myArray[1][3] and a definite error for myArray[4][1] as myArray[4] is nil and we are trying to get an element for a nil object.
Now that we know the basics of an array and a table, let us look at some
advanced functionalities.
First let us understand that tables are areas in memory that hold our data, so when we use the assignment operator " = " what we are doing is basically making the new variable also point to the same memory space.
To explain in detail,
local i = 1 local j = 2 print ( "i = " .. i ) print ( "j = " .. j ) j = i i = 3 print ( "i = " .. i ) print ( "j = " .. j )
You will notice that the values work as expected, but if we use this code
local myArray = { "item1", { "One","Two","Three", }, "item3" } print(myArray[1]) local test = myArray[2] test[2] = "Due" print(myArray[2][2])
You will see that the output is not what one would have expected, it should have printed "Two", but it prints "Due". So this helps us understand one very important thing, which was mentioned earlier, each table is nothing but a pointer to a memory location. So when we assign local test = myArray[2] it points to the memory location holding the table data. In general this is one gotcha, that a lot of developers get trapped into, this will not create a copy of the array/table. To *Duplicate* the table data, we cannot just assign the variable to the data.
So what do we do now?
Lua has some functions in-built to work with tables, these are
- table.concat()
- table.copy()
- table.indexOf()
- table.insert()
- table.maxn()
- table.remove()
- table.sort()
To make a copy of this array/table, there are a couple of ways to manage it, one of them is to create a new table and populate the elements in it.
The other is to use the built-in function table.copy, the only issue with this function is that it does what is called a "Shallow Copy", it copies the items from an array (as defined earlier) so if we have a table, it will not work. The strange thing with Lua tables is that there is no certain way to find out if a table is a table or an array. This creates a problem as to what function to use, as there are two functions to iterate though each item in the table/array, ipairs and pairs.
ipairs iterates over each numeric index of the array, returning the index number and the element, if the element is another table, then the table is returned instead of the primitive.
pairs on the other hand works with the tables (key-value-pairs) and return the key and the value.
local myTable = {item1 = "One", item2 = "Two", item3="Three"} local myArray = {"Eins", "Zwei", "Drei"} for k,v in ipairs(myArray) do print(k,v) end for k,v in pairs(myTable) do print(k,v) end
Let us also look at how to get the length of an array, the only way to actually get the array length is by counting the elements in the array. A missing element returns nil, so most functions stop counting once it finds a nil as in (with the above data)
print(#myArray) --> This should print 3 myArray[100] = "Hundert" -- Let us add an element no 100 print(#myArray) --> This will still print 3 print(table.maxn(myArray)) --> this will print 100So you see that both of these are wrong and not what we expect. The only way to correctly get the length of the same is to use the iteration pairs or ipairs and add to a counter to get the length as in
local function getArrayLength(theArray) local counter = 0 local i for _,i in ipairs(theArray) do counter = counter + 1 end return counter end local function getTableLength(theTable) local counter = 0 local i for _,i in pairs(theTable) do counter = counter + 1 end return counter end
Let us make an actual copy, not a reference
With these few tips and things we learned about tables, let us now create a copy of the table, not a reference to the table, but an actual copy.local myArray = { "item1", { "One","Two","Three", }, "item3" } myArray[100] = "Hundert" local function copyArray(thisTable) local result = {} local v for _,v in ipairs(thisTable) do table.insert(result,v) end return result end print(myArray[1]) local test = copyArray(myArray[2]) test[2] = "Due" print(myArray[2][2])
Till next time
This is it for this tutorial, play around with these to understand how tables work in Lua, in the next part we shall look at how to shuffle and sort our entries and I *might* even create a library for use in your apps to deal with tables.Please do feel free to make comments in the comments below, after all it will be you that will help drive these tutorials.
Image src : Google Desk
Excellent tutorial and explanations. Thank you!
ReplyDeleteCan you show me an example of a table which has three different colored boxes that links to another table which has coordinates and a print statement telling what colored boxes are linked to the other table?
ReplyDelete