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.

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 peculiarities

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.

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 items
With 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 100
So 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

Comments

  1. Excellent tutorial and explanations. Thank you!

    ReplyDelete
  2. Can 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

Post a Comment

Popular Posts