View unanswered posts | View active topics It is currently Thu Mar 28, 2024 4:26 pm



Reply to topic  [ 3 posts ] 
 Table Tutorial 
Author Message

Joined: Fri Sep 10, 2010 1:48 am
Posts: 666
Location: Halifax, Canada
Reply with quote
Post Table Tutorial
A Tutorial On Tables

Tables seem to be a confusing thing for a lot of people to grasp, I struggled with it for ages and I think most people trying to learn lua do too, which means they simply avoid them and thus lose the use of an incredibly versatile tool in lua coding.
So the purpose of this tutorial is to give a thorough understanding of tables, from start to finish. Thanks for reading.

Contents:
1. Intro to tables
2. Array tables and their uses
3. Accessing array table values
4. Dictionary and hash tables and their uses
5. Accessing dictionary/hash tables, the pairs for loop
6. Sorting tables
7. Advanced table uses

1. Intro to tables
Tables in Lua are very flexible and versatile, there are a lot of possible ways to use them and I'm sure I'll cover only a fraction of them here. However, the ultimate purpose of any such use is to easily and conveniently store and access information, particularly when compared to using simple variables for everything.
Tables are created in lua like any other variable, except that the value is an open curly bracket and a closed curly bracket, as follows:
Code:
mytable = {} --This creates an empty table

You can also create multidimensional tables, i.e. tables with tables inside (it's less complex than it may sound) similarly:
Code:
mytable = {{}} --This creates an empty 2-dimensional table, i.e. one with another table inside
mytable2 = {{{{{{{{}}}}}}}} --This creates an empty 8-dimensional table, i.e. one with 8 layers of tables inside, you should probably never be in a situation where you have to use something like this


That covers making a table, but tables are useless until you add items to them. There two ways to do this; table.insert and table[value] = item. The latter is generally more useful, though insert has its advantages. Ultimately, table.insert is simpler so it will be covered first.

table.insert is a built in lua function for tables, called in much the same way as, say, math functions (e.g. math.random, math.floor) or string functions (e.g. string.find, string.sub). As such, you need to provide it arguments in the following order:
Code:
mytable = {} --Make our table
myitem1 = "abc"; --Make an item to add to the table
table.insert(mytable, myitem1) --This adds myitem1, namely the string "abc" to the end of the table. There is an optional argument to specify the position in the table you want to add it to.
myitem2 = "def"; --Make a new item to add to the table
table.insert(mytable, 1, myitem2) --This adds myitem2 to position 1 of the table. Thus it is placed before myitem1 in the table and myitem 1 is shifted to position 2of the table
--The table's values would now be: "def", "abc"

The advantage of using table.insert can be seen when adding myitem2 to the table, it shifts any other items in the table over to make space for the newly added item instead of overwriting items or requiring you to shift everything yourself, the other method does not do this.

The more versatile method of adding items to a table is to use table[key] = item. This does pretty much the same thing as the previous method but it won't shift items. It is, however, shorter to type and allows for some very useful tables, which I'll get into later.
Similarly, you can add all the table's items when making it, by putting them inside the original curly brackets:
Code:
mytable = {"abc", "def", "ghi", {"jkl", "mno"}, "pqr"};
--As shown, your table doesn't have to only contain one type of value, you can have strings, numbers, other tables or even functions inside tables.


2. Array tables and their uses
The most straightforward way of using a lua table is to use it as an array, which is done by using integer numbers (i.e. 1,2,3,20,etc.) as keys when inserting values. You can insert your values in any order and you don't have to use consecutive numbers, though having a bunch of empty space in a table can slow down its use in some cases. Remember that lua tables start at index 1, so trying to insert something with 0 as the key will not work. Other than that, insertion is exactly like mentioned above:
Code:
mytable = {} --Make our table
mytable[1] = "value 1";
mytable[2] = "value 2";
mytable[20] = "value 20";
--The table's values would be "value 1", "value 2", nil, nil,..., nil, "value 20", where ... is 14 consecutive nil values.
--Note that you could also do all of this in one line, though that's inadvisable for large tables
mytable2 = {"value 1", "value 2", [20] = "value 20"};
--As you can see, when your value is added in order, you can just write it in, but if you want to skip numbers you have to specify which number to use for the value, in this case 20

Adding values one by one like this is pretty useless, since you could just as easily save them as variables and use those. Fortunately, you can use a loop to add values to a table, saving space and effort:
Code:
mytable = {} --Make our table
for i = 1, 20 do --Repeat 20 times, i will be used as the key for entering table values. It starts at one and each time the loop is finished, it goes up by one until it reaches 20.
   mytable[i] = "value "..tostring(i); --Set the table's value for i as "value [value of i]" using string concatenation
end
--The table's values would be "value 1", "value 2", "value 3",..., "value 20"

This makes tables far better than simple variables for large amounts of data.

3. Accessing array table values
Accessing values in lua tables is quite straightforward, in fact you've seen it already several times in this tutorial. If you want a specific value, you can access it in pretty much the same way you added it:
Code:
--Using the values entered in section 2
print(mytable[1]); --PRINT: value 1
print(mytable[20]); --PRINT: value 20
etc.

As you may have guessed, you can access tables values with a loop in the same way. Lua does have an additional method for accessing array tables, ipairs (short for iterated pairs):
Code:
--Using the values entered in section 2
--Simple for loop
for i = 1, 20 do
   print(mytable[i]..", i is "..i); --PRINT: value 1, i is 1; PRINT: value 2, i is 2; etc.
end
--ipairs loop
for i, v in ipairs(mytable) do
   print(v..", i is "..i); --PRINT: value 1, i is 1; PRINT: value 2, i is 2; etc.
end

You'll notice that both methods do exactly the same thing, however ipairs lets you access the values and their index very easily. It's also particularly useful when you're accessing tables within tables, since there's less difficulty keeping track of names.
However, ipairs is slower that a simple for loop by 1.5 or 2 times. But it's a bit nicer to use so if you're not working with a large table it's perfectly fine.

4. Dictionary and hash tables and their uses
Array tables are nice, but they're quite standard. Where lua tables excel (in my opinion at least) is in their use as dictionaries and, more importantly, hash tables. For more on hash tables, look here. Suffice to say they allow you to access individual elements of a table without having to know its numerical position in the table. Believe me when I say this is very, very useful for efficiency.
Dictionaries can be thought of as arrays with strings instead of numbers for their key. Lua provides some easy way of writing these in, so you don't have to keep track of quotation marks all the time:
Code:
--Let's say you want put together a table of fruit and their colours
fruittable = {};
--You can add values in either of the following ways, they're both completely equivalent
fruittable["apple"] = "red";
fruittable.banana = "yellow"; --This version uses lua's 'syntactic sugar' which lets you use .string instead of ["string"] for convenience
--You could also do this all in one line, lua also has an easy way of doing this too
fruittable2 = {["apple"] = "red", banana = "yellow"}; --Again the second value has no square brackets and quotations. Both ways are completely equivalent.

Dictionaries are nice, but hash tables are where this really shines. In lua they're essentially the same as any other table, except you can use just about anything you want as a key. And the best part is, they're no more difficult to make than any other sort of table:
Using CC style examples, let's say you have a number of a specific MOSRotatings on a scene and you want to save their position so you can move them around then put them back later. You can do this manually or with an array table, but the first takes up a lot of space and the second requires a lot of extra loops and work to make it actually correct. However, hash tables would make it really easy:
Code:
local mostable = {};
for mosrotating in MovableMan.Particles do
   if p.PresetName == "MyDesiredName" then
      mostable[mosrotating] = mosrotating.Pos;
   end
end
--You can then access them easily and move them back with with no difficulty, this'll be covered more in the next section

You're of course not limited to just a string or number of vector as the value, you could easily set the value as another table or a function or anything else, so you can store a lot of information about anything very easily:
Code:
local mostable = {};
for mosrotating in MovableMan.Particles do
   if p.PresetName == "MyDesiredName" then
      mostable[mosrotating] = {mosrotating.Pos, mystring = "A specific string", [12] = 12345, ["tableval] = {"A sub table", "with all sorts of values", Vector(123, 456)}, function() return 1 + 2 end};
   end
end
--This gives you the ability to store and access a large amount of information very easily

NOTE: The above method doesn't seem to work very well with actors, I think it's because CC is frequently changing their ID so you won't have the exact same value later when you want to access your information. For actors you should use something constant, like lifetime, sharpness or presetname.

5. Accessing dictionary/hash tables, the pairs for loop
Accessing individual values in dictionaries and hash tables is done much like it is for arrays:
Code:
--Using the tables from section 4
print(fruittable["banana"]); --PRINT: yellow
print(fruittable.apple); --PRINT: red
--Given a local variable 'mos' which is one of the mosrotatings in your table
print(mostable[mos]); --PRINT: Vector(x, y)
--In the second case - PRINT: table#aefoc2 (if I remember correctly, the random numbers/letters indicate the memory location of the table, they're irrelevant for our purposes)

Accessing multiple values at once is much the same as in array tables, however you can't use a simple for loop, since there are no numbers to go through. Instead you use the pairs method to go through the table:
Code:
--Using the tables from section 4
for k, v in pairs(fruittable) do
   print(k.." - "..v); --PRINT: apple - red; PRINT: banana - yellow
end
for k, v in pairs(mostable) do
   print (k.." - "..v); --PRINT: MOSRotating, MyDesiredName - Vector(x, y); PRINT: ...
end
--In the second case for the mostable, you could use access each subtable's values individually or use another for loop to print all the values
for k, v in pairs(mostable) do
   print(v[12]); --PRINT: 12345
   print(v["mystring"]); --PRINT: A specific string
   print(v.tableval); --PRINT: table#asfw123sd
   print(v.tableval[1]); --PRINT A sub table
   for k2, v2 in pairs(v) do
      print(k2.." - "..v2); --PRINT: 1 - Vector(x, y); PRINT: mystring - A specific string; etc.
   end
end
Take note here of the notations for entering and accessing table values, it can be easy to mix up what enters and accesses a string and what enters and accesses a value or variable:
Code:
--Inserting
local mytable = {a = 123, [a] = 456}; --The string "a" has value 123 while the variable a has a value of 456
local mytable2 = {12 = 789, [12] = 012}; --The string "12" has value 789 while the value at index 12 (i.e. the number 12) has a value of 012
--Accessing
print(mytable.a.."  "..mytable["a"].."  "..mytable[a]) --PRINT: 123  123  456 - mytable.a is the same as mytable["a"], but mytable[a] uses the variable a
print(mytable.12.."  "..mytable["12"].."  "..mytable[12]) --PRINT: 789  789  012 - mytable.12 is the same as mytable["12"], but mytable[12] uses the number 12

Also note that the pairs iterator will not necessarily give you your values in the order you added them in. Do not use pairs if you need to access values in your table in the same order you inserted them.

6. Sorting tables
I'm mainly adding this because it's easy to overlook, lua tables have a built in sorting method, so you can organize things numerically or alphabetically without having to do it yourself. I assume they use an efficient sorting method so it's probably the best way to sort things in lua.

table.sort(mytable) will sort a table using the < operator, so it will automatically work with string and number values. It'll probably give issues with things like Vectors and other CC specific values.
Fortunately, you can use table.sort(mytable, sortfunction) where sortfunction is a function which takes in two argumens and returns true if the first argument should come before the second in the sorted array (i.e. function sortfunction(v1, v2) returns true if v1 < v2 and false otherwise).
Note that table.sort can only be used with array tables, since you can't sort dictionary/hash tables (there's no order to them so sorting them wouldn't do anything).

If you can't think of a use for sorted tables, how about proximity checks? Instead of looking through all actors and checking if the SceneMan:ShortestDistance(start, actor.Pos, false) is less than the previous smallest distance, you could add them all to a table, sort it and pull out the first. It saves a lot of lines (though truth be told it's probably less efficient).

Look here for more specific stuff about sorting:
http://www.lua.org/pil/19.3.html

7. Advanced table uses
This is only the surface of lua tables, there's a whole bunch more you can do with them, which I haven't used enough to feel qualified to write about. If you're new to tables or lua, I would suggest avoiding this stuff, but that's your call entirely.
You can do stuff with metatables, including pseudo-OOP. A lot of CC's lua stuff uses metatables, so you can effectively break the entire game (until restart) with 1 or 2 lines of lua code!

I'll put a few links for those who want to look into this stuff (google it if you want more):
Metatables
Lua pseudo-OOP
Weak tables, these are more about garbage collection in lua, but it's still interesting
More metatables
More OOP
More weak tables


More Information
Finally, if you want more table tutorial stuff, check out the official lua ones:
http://lua-users.org/wiki/TableLibraryTutorial
http://www.lua.org/pil/11.html

Needless to say, credit for any information in these and all other links I've posted goes to the people who created them. They helped me a lot with learning how to use tables and I'm sure they'll help other people too.


Thanks!
Thanks for reading, if I made any mistakes or you think there's anything I need to expand on or clarify please let me know.
If you have any questions, please don't hesitate to ask, if I think it's worthwhile I'll put up an FAQ for this too based on questions people ask.


Last edited by Bad Boy on Mon May 12, 2014 2:47 am, edited 1 time in total.



Wed Mar 26, 2014 6:29 pm
Profile

Joined: Fri Sep 10, 2010 1:48 am
Posts: 666
Location: Halifax, Canada
Reply with quote
Post Re: Table Tutorial
Now on steam with its slightly nicer formatting:
http://steamcommunity.com/sharedfiles/f ... =259058273

In case anyone's curious, there haven't been any updates to this other than typo fixes, though there were a painful amount of those. I think it's justified since I wrote most of this around 2 - 5 AM.


Last edited by Bad Boy on Mon May 12, 2014 2:48 am, edited 2 times in total.



Mon May 12, 2014 2:45 am
Profile
User avatar

Joined: Fri Aug 20, 2010 4:45 am
Posts: 911
Location: No Comment.
Reply with quote
Post Re: Table Tutorial
Bad Boy wrote:
Now on steam with its slightly nicer formatting:
http://steamcommunity.com/sharedfiles/f ... =259058273

In case anyone's curious, there haven't been any updates to this other than a few typo fixes.


at lest someone is paying attention to guides section, good job!


Mon May 12, 2014 2:47 am
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 3 posts ] 

Who is online

Users browsing this forum: No registered users


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by STSoftware for PTF.
[ Time : 0.148s | 15 Queries | GZIP : Off ]