Skip to content
Tags

26. Tables

April 7, 2013

Tables are extremely important in Codea, but I’ve delayed writing about them, because there are some pretty good explanations around already. Tables belong to the underlying programming language Lua, rather than Codea, and there is quite a lot of support on the Internet, because Lua is used as a scripting language in several games.

There is a nice introduction here. I suggest you start with that. There are many other tutorials that can be found, such as here. If you want more advanced techniques, try the official manual here.

The aim of my blog is to explain difficult concepts and make it easier to learn Codea, not simply to repeat good material from elsewhere. So I don’t want to start at the very beginning, because that’s already been done for you. Instead, I want to explain some of the things that make tables hard to use.

This is quite a long post because I really want to try to explain as clearly as possible.

So if you don’t know anything about tables at all, please start with the links above, and look at some actual Codea examples (many of which can be found in my previous posts).

Important table concepts

Perhaps the most important concept is that Lua just doesn’t have the kind of arrays I’m used to, where each element is numbered. Yes, you can say a[3]=5, the same way you would in many other languages, but that doesn’t mean that 5 gets stored in the 3rd element of the array a. Instead, Lua stores the number (but not necessarily after a[2] and before a[4]), and associates it with the number 3 so it can find it again.

An example may help.

Arrays

Imagine you are running a coat locker, where people leave their coats before a show. The normal way to do this would be to pre number all the lockers 1,2,3,… and hand out tags to people, making sure to put their coats in the locker with the same number as the tag. This is how normal arrays work. The lockers are numbered in advance and run in integer sequence.

Hash tables

An alternative is not to number the lockers at all. Instead, when someone brings a coat, you put it in the first empty locker, and pick up a pair of matching tags. One goes to the person, the other goes on a hook on the locker. This is a more flexible approach, but you probably wouldn’t expect to see it in real life because you’d spend a lot of time hunting for the right tags on lockers when people came back for their coats, ie the pre numbered system makes retrieving coats easier.

However, businesses like dry cleaners have to use this approach to identify owners of clothing – ie they attach a tag to your clothes and give you a matching tag – because they don’t have lockers at all. When you come for your clothes, they have to fish through their racks to find the matching tag.

If you do use matching tags like this, and you have thousands or millions of them, clearly the main problem is going to be finding the tags you want, if they aren’t in any kind of order. Fortunately, computers know to do this quickly, using a concept called hash tables.

Lua uses the dry cleaning approach, not the coat locker approach. Let’s see how.

How Lua works

Let’s do the easy part first.

Most languages have “dictionary” objects, where you can insert a “key” and a “value”. For example, if we were programming a lot of balls bouncing around a screen, we would probably store an x and a y value, and movement data, for each ball, something like this, for a given ball

 ballinfo = {x=300,y=200,angle=25,velocity=200}

So x is a key, and 300 is its value, and the same for the other pairs. We can then look up the info simply with ballinfo.x or ballinfo.angle, etc.

This is how Lua stores tables anyway, so you could say it handles everything using dictionaries. And if you want a dictionary, then Lua works pretty much as you would expect.

 
    ballinfo = {} 
    ballinfo['x']=300
    ballinfo['y']=200
    print(ballinfo.x) --prints 300

This example is exactly the same one as above. It’s just a different way of writing it.

But suppose you want an array like this

 
    t = {} 
    t[1]=3 
    t[2]=6 
    t[3]=9
    print(t[2]) --prints 6

Lua treats the numbers inside the square brackets as tags. It doesn’t care that they’re integers, or in sequence. It would happily accept t[2.714]=6 or t[“frog”]=6 instead of t[2]=6.

So when you’ve created the table above and you write some code to loop through it, eg

    for i=1,#t do
        print(t[i])
    end

you may think you are stepping through an array, but what is really happening is that you are giving Lua tags (ie 1, 2, 3) and for each tag, it is finding the matching tag on the items stored in the table. So Lua doesn’t regard a tag of 1 as being the first item in the table, because there is no such thing.

You can also create the table above like this – note how you have to enclose the tags with square brackets so Lua knows you mean them to be tags and not numbers.

    t = { [1]=3, [2]=6, [3]=9 } 

Or you can create it like this, with no tags at all, just values

    t = { 3,6,9 }                 

in which case, Lua will create its own tag for each value, in the sequence 1,2,3…, ie 3 is tagged with 1, 6 is tagged with 2, and 9 is tagged with 3, which gives the same result as the earlier examples.

Looping through a table of items

If your table has tags which are numbered in sequence, you can use a normal array loop, like

    for i=1,#t do
        print(t[i])
    end

If you want to loop through a dictionary table (eg with data like dict[“bird”]=”fly”), the tags are not numeric, so Lua provides a special pairs function

    --this example is from the Lua wiki
    t={[3]=10,[1]=3,[4]=17,[2]=7,pi=3.14159,banana='yellow'}
    for key,value in pairs(t) do print(key,value) end
    --output
    3       10
    1       3
    4       17
    2       7
    pi      3.14159
    banana  yellow

This will list all the key-value pairs in the table, in no particular order.

Finally, Lua provides a variation on pairs, ipairs, which

  • lists all key value pairs where the key is an integer
  • lists keys in number order
  • .
    So

        t={[3]=10,[1]=3,[4]=17,[2]=7,pi=3.14159,banana='yellow'}
        for key,value in ipairs(t) do print(key,value) end
        --output
        1       3
        2       7
        3       10
        4       17
    

    so ipairs only works with integer keys. The way I remember this is that I’m used to looping through numbered arrays using i as the counter, so the function starting with i, ipairs, is the one that uses numbered keys.

    Miscellaneous

    Lua’s approach to tables is useful is if you want to leave gaps. For example, we can say t[900]=5, and Lua does not create space for 900 entries in the table – it just adds one item. In many programming languages, you would have to make space for all the items between 3 and 900.

    There are some slight inconveniences – for example, to create a 2D table, you first create a table, then make each of its items a table. But I haven’t found that to be much of a problem.

    From → Programming

    Leave a Comment

    Leave a comment