Welcome to the PtokaX Wiki!


This wiki is devoted to let users share information on the great hubsoft PtokaX. However, it is not limited to PtokaX, it is destined to share and discuss information on different parts of the LUA programming language, but the site is NOT intended to be a replacement for the primary LUA Board aka the PtokaX Portal, nor the secondary LUA Board or the PtokaX resources.

If you’re not familiar with wikis then in short: they are user-contributed sites: pages can be edited by (almost) anyone. As such, there is always kind of up-to-date and (hopefully) proper content. They are better than forums, since relevant pieces of information are on the same page. Do not hesitate to share your knowledge, and we all hope you can learn and teach a lot here! — bastya_elvtars



This will explain the use of tables in Lua.

To start off, let's see the HOWTO of lua master plop.

Tables & Arrays

Introduction to Tables and Arrays in Lua by plop

Like all the other How-To's were again gone need the lua command line for the examples.

In C/C++ there are tables and array's, in lua the array's are also tables.

array = { "string1", "string2", "string3", "string4", "string5" }
 
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }

The table shown here is called an associative table, as the thing before the = is associated with the part after it. Now, most people, would expect that I'm going to start by explaining the arrays first, I'm not going to do that. Because, array's are tables to it's easier initially, to explain the tables. You'll then see easier the link between those two. The table I have made uses numbers as indexes (keys) and strings as values.

Chapter 1: Tables

We're going to start really easy by just printing out all the value's in the table. I used numbers as key's we can retrieve them with this:

tbl[number].

Let's do a simple loop.

print("example 1")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
for index = 1,5 do 		-- do a loop of 5 steps.
print(tbl[index])
end

Now this worked fine but you can allready see a problem, what if there would be more key's in the table?? Indeed, those wouldn't be printed. So, we need a different kind of loop.

print("example 2")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
for key,value in tbl do 		-- do a loop for aslong as there are key's with value's in the table.
print(tbl[key])
end

This method opens up another way. Now, we can also grab the key from the table, which can be handy to have, sometimes. The loop states that there is a key and a value, we can use them directly. Let's print the matching key now along with the value.

print("example 3")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
for key,value in tbl do 		-- do a loop for aslong as there are key's with value's in the table.
print("key= "..key.." and has the value: ".. value)
end

Now we know how to process a table. So, let's start with stuffing things into it. Adding things is really simple:

table[6]="string6"

Can't make it more complex than this,… or can I?? Yes, I can. As i'm lazy, we're going to use a loop to extend the table to hold ten keys/values. To show the new table the same loop from the last example is going to be fine for using it also in this.

print("example 4")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
for index=6,10 do 		-- start a loop from 5 steps starting with index number 6.
tbl[index]="string"..index
end
-- next execute the loop from the last example.
for key,value in tbl do 		-- do a loop for aslong as there are key's with value's in the table.
print(tbl[key])
end

Now, let's do the opposite of adding things to the table. We're going to remove keys from 1 to 5. A table can hold everything BUT nil, so all we have to do it declare the keys to be nil.

tbl[1]=nil

We're going to extend the last example with a loop to do this.

print("example 5")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
for index=1,5 do 			-- start a loop of 5 steps starting with 1.
tbl[index]=nil
end
for index=6,10 do -- start a loop from 5 steps starting with index number 6.
tbl[index]="string"..index
end
-- next execute the loop from the last example.
for key,value in tbl do 		-- do a loop for as long as there are key's with value's in the table.
print(tbl[key])
end

Now you might notice that something weird has happened (not on everyone though).

string8
string9
string10
string6
string7

The order is messed up, but no reason to panic at all. This isn't a problem, this is just how lua works. When we remove things we get a free wasted space, this is filled by moving something else to it. But, do remember this, you're going to see the same on array's and there it can cause problems. but before we're going to discuss that we're going to do something that the smartasses have already seen. the first loop removes keys 1 to 5, this is the full table. So, instead of wasting time on the loop we could drop the full table in the garbage bin and declare a new empty table. This, is nearly the same as removing a key,

tbl = nil

drops the table and

tbl = {}

builds a new. Let's do a example again.

print("example 6")
tbl = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }
tbl = nil
tbl = {}
for index=6,10 do 		-- start a loop from 5 steps starting with index number 6.
tbl[index]="string"..index
end
-- next execute the loop from the last example.
for key,value in tbl do 		-- do a loop for aslong as there are key's with value's in the table.
print(tbl[key])
end

now we basicly finished the table part (there are some other way to adress them but not gone discus those here).

Chapter 2: Arrays

Allready told you that array's are tables too, now let me explain how that is posible. for us humans a array looks like this:

array = { "string1", "string2", "string3", "string4", "string5" }

but lua sees it as

array = { [1]="string1", [2]="string2", [3]="string3", [4]="string4", [5]="string5" }

as you can see lua uses indexes for them to, but we never see them in the array. this makes it all a bit spooky, and as a result you might think that it works the same as a associative table but no. array's have there own methods and they can cause big problems if you use them incorrect, the example's are gone show all those things.

Example 6

Let's start with just showing all the value's in the array 1 by 1.

print("example 6")
array = { "string1", "string2", "string3", "string4", "string5" }
for index=1,5 do
print(array[index])
end

now this looks exactly the same as the table version. you can allready start to see that tables and array's are the same in lua. on example to we changed the loop so it would work even if the table held more then 5 things.

Example 7

to make the link between array's and tables totaly clear we're going to use the code from example to again.

print("example 7")
array = { "string1", "string2", "string3", "string4", "string5" }
for key,value in array do
print(array[key])
end

As you can see it works fine. But it's not a nice way of doing it (should be avoided if posible). Especialy if you think that arrays have a trick up there sleeve which could be used here. #array gives you the number of value's stored in the array.

Example 8

let's use take the code from example 6 but insert getn.

print("example 8")
array = { "string1", "string2", "string3", "string4", "string5" }
print("the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

Now we're getting to the hard part, adding removing things to/from the array. You might do it the same way as with tables and it's gone work untill a certain point. The reason for this is that Lua excepts all types of things in a single table.

mixedtable = { "string", [1]="string", ["string"]=2, [15]= function(user, data) dosomething() end, table2={1,2,3} }

As you can see on the above line you mix all sorts, Lua won't complain at all. But, table.getn works correctly only on a true array. So, think carefully about it before you try to do such a thing. Now,… because of this Lua has some special commands to insert and remove things from an array, table.insert and table.remove. Let's look at table.insert to start with.

table.insert(array,position,value)

The position is something new for us and is optional, if you leave it away it's going to insert the values at the end of the array. If you use it it's going to place it on the matching position. More, on this, later on.

Example 9

Let's take a look at an example based on the previous example 8, again we're going to insert 5 strings.

print("example 9")
array = { "string1", "string2", "string3", "string4", "string5" }
print("the array has "..table.getn(array).." value's stored in it")
for index=6,10 do
table.insert(array, "string"..index)
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

As you can see, the strings are added to the array and are in the right order. The table.getn is automaticly updated to the new amount of value's stored in the array (the value that table.getn returns is actualy stored in the array in the last not used space). Now let's try to remove the first five strings by using the same kind of loop we used for removing things from the table in example 5.

Example 10

print("example 10")
array = { "string1", "string2", "string3", "string4", "string5", "string6", "string7", "string8", "string9", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
for index=1,5 do
table.remove(array, index)
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

Now it's about time to panic, has Lua lost it's mind ???

the array has 10 value's stored in it
now the array has 5 value's stored in it
string2
string4
string6
string8
string10

What was removed were not the first 5 but every odd number, whats going on here?? The answer is simple. The string1 has index 1, but when we remove that string2 gets the index 1.

Example 11

After every insert/remove the key's are updated. To solve this we can do a couple tricks. Let's start simple by just keeping removing index number 1, for five times.

print("example 11")
array = { "string1", "string2", "string3", "string4", "string5", "string6", "string7", "string8", "string9", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
for index=1,5 do
table.remove(array, 1)
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

Now this works fine, but what if we just want to remove the indexes 3, 5, 7 and 9. We can't use a loop here and we can't just remove them in the given order??

Example 12

The trick is to work backwards, if we first remove index 9 then 10 becomes 9 but 7 stays 7. Let's take a look at it.

print("example 12")
array = { "string1", "string2", "string3", "string4", "string5", "string6", "string7", "string8", "string9", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
table.remove(array, 9)
table.remove(array, 7)
table.remove(array, 5)
table.remove(array, 3)
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

That worked. Now let's take a step back to example 10. Why ?? Because it could have worked if we would have done what we just learned.

Example 13

If we run the loop backwards it's going to work perfectly.

print("example 13")
array = { "string1", "string2", "string3", "string4", "string5", "string6", "string7", "string8", "string9", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
for index=5,1, -1 do 		-- start a loop begining with 5 and counting backwars to 1, the -1 tells the loop to count backwards
table.remove(array, index)
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

As you can see, the result is now just what we wanted, the first 5 values are gone.

Example 14

Now, let's take a closer look at ”“table.insert”” again but now with position number. Going to get a bit harder now as we're going to fix the broken array from example 10, and by abusing the re-indexing, we're going to use the same backward loop. Let's see what happens….

print("example 14")
array = { "string2", "string4", "string6", "string8", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
for index=5,1, -1 do 		-- start a loop begining with 5 and counting backwars to 1, the -1 tells the loop to count backwards
table.insert(array, index, "string"..index)
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

Nearly correct, they are on the right place just the strings are wrong. Logical as we used the index from the loop.

Example 15

Let's fix this to end this How-To.

print("example 15")
array = { "string2", "string4", "string6", "string8", "string10" }
print("the array has "..table.getn(array).." value's stored in it")
number = 9 			-- declaring number to be 9 as it's the first string number we're going to  need
for index=5,1, -1 do 		-- start a loop begining with 5 and counting backwars to 1, the -1 tells the loop to count backwards
table.insert(array, index, "string"..number)
number = number - 2 		-- subtracting number by 2 as we need to skip all even numbers
end
print("now the array has "..table.getn(array).." value's stored in it")
for index=1,table.getn(array) do 		-- start a loop starting with 1 and ending with the highest key stored in the array
print(array[index])
end

Now the array is fixed, in a nice orderly way, as it was on the start of example 10.

I hope you enjoyed it and learned to master tables and array's. Happy Scripting.

plop

More On Tables and Arrays

This HOWTO shows a bit more advanced usage of tables/arrays. — bastya_elvtars

Tables and data-storage

Tables/arrays are most commonly used to store data. We might want to retrieve the data sometimes. :-)

Let's assume that we have a table where keys are some cool guys, and values are their wives (not essentially meaning valuable wives though).

wives=
  {
    ["Joe"]="Tina",
    ["Ben"]="Natalie",
    ["Henry"]="Liz"
  }

Now let's get who's the wife of Joe.

girl=wives["Joe"]

girl will be “Tina”.

OK, we have a friend , named Tim, who married Shirley. Regardless of the (dis)advantages of the procedure, we have to include them in this table, cause we are pedant.

wives["Tim"]="Shirley"

While we were bothering with this issue, Ben and Natalie divorced. Let's just remove the relevant entry!

wives["Ben"]=nil

Well, so far it seems pretty simple. The table now looks like:

wives=
  {
    ["Joe"]="Tina",
    ["Tim"]="Shirley",
    ["Henry"]="Liz"
  }

Now comes the hard part: Joe marries Natalie too, and has 2 wives. This is a crime, the punishment is having 2 mothers-in-law. Nevertheless, we should still be up-to-date. What should we do? Well, tables can also contain arrays (as well as any value). Let's just see how we can include this miserable Joe:

wives["Joe"]={"Tina","Natalie"}

But Natalie is not a devoted one, so she divorces again. Handling this issue now invokes array-specific functions:

table.remove(wives["Joe"],2)

… and Natalie is history.

OK, this was a joke, everything is fine, the 2-on-1 works, but how do we know, whose wife is Natalie? Well, then we introduce a table structure like this:

wives=
  {
    ["Joe"]=
    {
      ["Tina"]=1,
      ["Natalie"]=1,
    }
    ["Tim"]=
    {
      ["Shirley"]=1,
    }
    ["Henry"]=
    {
      ["Liz"]=1,
    }
  }

Note that every guy has a table associated with his name from now on, just in case they wanna follow Joe's example. OK, then comes some innocent guy, asking: “Whose wife is Natalie?” And you have to answer him. Let's see how you can satisfy him:

for a,b in pairs(wives) do
  if a["Natalie"] then
    answer=a
  end
end
 
print(answer or "She is single.") -- if no answer, then she is single.

And the guy gets an answer.

Tables can be addressed in a different way:

tbl=
  {
    item1=1,
    item2="sumthin",
  }

Here we refer to items as table.item1, table.item2 etc. You can, however, refer to them as table[“item1”] too.

:!: If addressing tables this way, you should always have proper variable names nested, otherwise you will get an error.

Now, play with this addressbook sample, try getting values from it, try to find the best way. It's up to you.

addressbook=
  {
    ["John Smith"]=
    {
      Date_Of_Birth="1977. 07. 28.",
      Phone=
      {
          "+1122334455",
          "+1122334466",
        },
      Address="7 Mary St., Nowhere",
      Zip=0000,
      Occupation="Soup-brewer",
    },
    ["James Wilson"]=
    {
      Date_Of_Birth="1966. 01. 15.",
      Phone=
      {
          "+1122334477",
          "+1122334488",
        },
      Address="7 Lincoln St., Citytown",
      Zip=2222,
      Occupation="Ice-welder",
    }
  }

Array tricks

LUA has some tricks on arrays that are good to know, because they make your life easier.

table.concat

First one is the table.concat function, which I am sure you will like. It concatenates (merges) thean array, like:

arr={"I ","am ","playing ","with ","arrays."}
 
print(table.concat(arr))

:!: The array can only contain string and numeric values,otherwise you get this:

bad argument #1 to `concat' (table contains non-strings)

You saw that most words have a trailing space. Is it really necessary? No, it isn't. table.concat gets a second argument, which is the separator for concatenation. Let's just change the above code a bit by removing the items' trailing spaces, and give space as sepatrator for table.concat:

arr={"I","am","playing","with","arrays."}

print(table.concat(arr," "))

See? I told you that you would like it. ;-)

unpack

This is another handy tool, cause it returns the array elements. It is good to have, cause it's handy when feeding a function with arguments whose number varies even inside the calling function.

function Sum(a,b,c)
  if b then
    if c then
      return a+b+c
    else
      return a+b
    end
  else
    return("How could I summarize a single number?")
  end
end
 
function GetNums()
  print("Please give me numbers.")
  local args
  while not args do
    args=io.read()
  end
  local arr={}
  for w in string.gfind(args,"(%d+)") do
    table.insert(arr,w)
  end
  print(Sum(unpack(arr)))
end
 
GetNums()

Another great use is in math.max or math.min.

This will prompt for numbers, enter them separated by non-number characters. FIXME This example is sloppy. If somebody can make a better one, feel free.

Discussion

Please discuss all the above here. It will probably help others, and keeps the community organized.

Checking values in a table

Anyway to do this without having a static interger variable. ? E.g. something like this to remove wife Natalie from Joe.

for a table.getn(wives) do
     if string.find("Joe", wives) then
      for b in pairs(wives) do
        if b["Natalie"] then
        table.remove(wives[a],[b])
      end
    end
  end
end

Or won't this work / or have i gone a really bad way about doing this ?

for i,v in wives["Joe"] do
  if v == "Natalie" then
    table.remove(wives["Joe"],i)
  end
end


and pass the doobie, bogart :-P

for i,v in pairs(wives["Joe"]) do
  if v == "Natalie" then
    table[i]=nil
  end
end


Without a function call, it is faster. :P — bastya_elvtars

As an alternative way (one not doing a for loop through the whole table), would this work ?
if (wives["Joe"]["Natalie"] ~= nil) then
    wives["Joe"]["Natalie"] = nil
end


If this is good, only the middle line should be needed, for the particular example. The other 2 lines are just as an error prevention check.

if wives["Joe"] and table.getn(wives["Joe"]) > 0 then
    wives["Joe"]["Natalie"] = nil
end


This way we just check if Joe is married at all. — bastya_elvtars


Personal Tools