Add Me!Close Menu Navigation

Learn Lua the Hard Way – Tables

Tables are the most important data structure in Lua thanks to their flexibility, hence we dedicate an entire post to the use of tables. In this tutorial, you will learn how to create and manipulate tables and dictionaries and how to iterate over a table using for and while loops.

1. Other Tutorials

Chapters 1–5 → An introduction to Lua.
Chapter 11. → The project team problem part 1

2. Table of contents

3. Chapter 6: Tables

Being able to work with singular pieces of data like numbers and strings is all good and fun, but sometimes we may need to use multiple objects at the same time. What if we wanted to find the average height of a bunch of cats so we can make crude references to “long cat is long”, but we need some kind of exhibitionary evidence? Sure, if we have five cats, we can just put them each in a separate variable and take the average of them:

cat1 = 10
cat2 = 11
cat3 = 12
cat4 = 8
cat5 = 100 -- LONG CAT IS LONG

print("The average length between these cats is ", (cat1 + cat2 + cat3 + cat4 + cat5) / 5)

But what if a sixth cat comes along? Well you’re going to have to add it into the group as well because he’s meowing ever so cutely and you like to imagine yourself as the protector of cat equality. But upon seeing the sixth cat all smug and high that it was allowed into this exclusive club, cat7 and cat8 became discontent and they too try to “fit in” with everyone else… Sooner or later, you’re just going to be all like “fuck this, I’m not gonna be a bitch to some cats” and stop adding cats into your program because it’s been a long day, the meowing is getting on your nerves, and you’ve realized that the “long cat is long” joke is getting kind of old. But what about poor ole cat256? He’s got no job and an entire family of kittens and Ms. cat256 to feed. You’ll be labeled an enemy of the working cats and will be hated for the rest of your life (at least by 4chan).

Luckily, there’s a solution to situations where you either need to work with a massive amount of data or need to be able to grow your data once the program begins running.

Tables are magical entities in Lua. You can put anything you want in them, for example, your mother’s phone number, your employer’s address, the cost of purchasing a shotgun at your local friendly K-mart, and the probable date that you will receive your pink slip from the said employer. All in all, a table’s use can range anywhere from questionably legal to full-on awesome. In this case, we will be putting cats into our table:

cats = {10, 11, 12, 8, 100}

Here, we use the usual syntactical construct for assigning variables. However, rather than a number or a string, we’re assigning a table to the variable cats. A table is a grouping of elements that starts with a left bracket ({) and terminated with a right bracket (}). Individual elements of this table are separated using commas (,).

Elements of this table can also be retrieved later on using the “subscript notation”.

cat1 = cats[1]
cat3 = cats[3]

In the above code, the square brackets ([n]) is a subscript, which in formal mathematics denote the n-th element of a sequence or a table. By putting the subscript ([n]) after the table name (cats), we’re indexing into the table, or we’re returning the n-th element of the table.

So in order to find the average of these five cats, we would need to write:

cats = {10, 11, 12, 8, 100}
print("The average height between these cats is ", (cats[1] + cats[2] + cats[3] + cats[4] + cats[5]) / 5)

Output:

The average height between these cats is        28.2

Additional exercises:

  1. If you need to add a sixth cat whose height is 28, what would be the average of all six cats?
  2. Remember how you can use the # symbol to find the length of a string? Try it on a table as well. What will happen if you printed #cats?
  3. Can you add different types of data into a table? For example, can you have {“Lee”, 19}?
  4. What about adding tables into tables? Can you think of situations where this might be useful?

4. Chapter 7: Loops

As you can see from the above example, manually indexing into a table isn’t very elegant or efficient. What we need is a way for the computer to loop through every element of that table and then take the sum of these elements. It’s a good thing that we’re using a programming language to do this.

While Loops

A while loop will keep on executing the same thing until certain conditions or predicates are satisfied.

while CONDITION do
	...
end

In this case, as long as CONDITION is true, … will execute. But as soon as CONDITION becomes false, the loop will stop.

x = 1
while x < 10 do -- (x < 10) is the CONDITION 
	print(x)
	x = x + 1 -- We need to increase x by one each time.
end

Output:

1
2
3
4
5
6
7
8
9

Because (10 < 10) is false, as soon as x becomes 10, the loop exits, so 10 is never printed out.

For Loops

There are two ways to create a loop using the for keyword, we will focus on the more general method.

If you want to loop through a range of numbers (for example, going from 1 to 100), you can use the following construct:

for i=1, 10, 1 do
	print(i)
end

Output:

1
2
3
4
5
6
7
8
9
10

In this example, i=1 is the starting number, 10 is when the loop ends, and the last 1 is the step size. Thus, if we want to print all of the odd numbers, we can use

for i=1, 10, 2 do
	print(i)
end

Output:

1
3
5
7
9

Accordingly, we can also loop through every single element of a table if we know the size of that table. We can find the size of a table using the hash mark operator (#).

cats = {10, 11, 12, 8, 100}
sum = 0
for i=1, #cats, 1 do
	sum = sum + cats[i]
end

print("The average height between these cats is ", sum / #cats

Output:

The average length between these cats is        28.2

The (#cats) returns a number that corresponds to the size of the table (5), and the for loop iterates from 1 to #cats (5) and adds each element from the table of cats into the variable sum. We then take the average of sum by dividing by the number of cats (#cats).

Additional exercises:

  1. Print out all of the even numbers between 1 and 10. How about between 1 and 11? Do they display the same set of numbers?
  2. Print every number backwards from 10 to 1.
  3. Add a sixth number into the cats table and find the average of that table now. How much code did you have to edit? Can you see why for loops work really well with tables?
  4. In mathematics, the factorial function of n returns the product of every number between 1 and n (factorial of 3 = 3 * 2 * 1, factorial of 10 = 10*9*8*7*6*5*4*3*2*1). Write a program that prints out the factorial of 100 (9.3326215443944e+157)
  5. If you write for i=1,100 do print(i) end, will you get an error?
  6. What will happen if you write while true do print("Infinite loop.") end?
  7. What happens if you write for i=1,2 do i=1 end? Will this produce an infinite loop?
  8. What will happen if you write
    while true do
    print("Infinite loop.")
    break
    end
    ? What does the break keyword do?

5. Chapter 8: For Loops with Tables

A second construct for a for loop will only work with tables. This kind of a loop takes advantage of a feature in the language called an iterator (or generator), which is an advanced topic. But at its simplest, we can iterate through every element of a table using the ipairs() function.

for i,v in ipairs(cats) do
	print(i, v)
end

Output:

1       10
2       11
3       12
4       8
5       100

As you may have already figured out, this for loop sets i as the counter (index) of the table and v as the value of the elements. This is nearly equivalent to:

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

Additional exercises

  1. Using only ipairs, find the average height of the cats.
  2. What will happen if you use for i,v in pairs(cats) do print(i,v) end? Compare the output between ipairs and pairs.
  3. In probability theory / statistics, one can calculate the standard deviation of a set or a table of numbers by subtracting every element of a table with its average and taking the squareroot of the sum of the squares of each element. (IE: stdev of {1,2,3} = math.sqrt( (1-2)^2 + (2-2)^2 + (3-2)^2 ) where 2 is the average of that table. Write a program to calculate the standard deviation of {96, 100, 75, 58, 91, 78, 81, 85, 70, 69, 83, 74, 80} where math.sqrt(n) returns the square root of a number.. (Average = 80, Standard Deviation = 39.77)

6. Chapter 9: Tables as Dictionaries.

As we all know, a dictionary is a record that creates a mapping (relation) between a word and its definition. These types of relation in which one object is mapped to another is also very useful to programmers. Did you know that tables can be used as a dictionary for Lua data as well?

dictionary = {hello = "used to express a greeting ", world = "the earth or globe, considered as a planet"}

print(dictionary["hello"], dictionary["world"])

In fact, you can also add in new definitions once you’ve declared the dictionary:

dictionary["cat"] = "a small domesticated carnivore "

And that these definitions can be of any type as well:

dictionary["lua"] = {"A programming language.", "The moon in Portuguese."}

And that dictionaries can be mixed with numerical indices:

dictionary["lua"] = {"A programming language.", "The moon in Portuguese.", category = "This is also a dictionary :O"}

In fact, a dictionary doesn’t have to be defined using strings, you can use anything:

dictionary[1] = "A programming language."
dictionary[{1,2,3}] = "wait, wtf is this?"

Note that when you’re using a numerical index, the dictionary doubles as a list so you can actually use ipairs to cycle through the elements:

dictionary[1] = 1
dictionary[2] = 2
dictionary[3] = 3

for i,v in ipairs(dictionary) do
	print(i,v)
end

Output:

1
2
3

And if you want to cycle through all of the elements of the dictionary, you can use the pair function.

for key, val in pairs(dictionary)
	print(key, val)
end

Additional exercises

  1. Write a dictionary that contains itself.
  2. One of the most useful dictionary used in the Lua language is the table that contains all of the global variables itself. Try the following: for key,val in pair(_G) do print(key) end. Now create a new variable – a = 3. What is _G[“a”]?
  3. If you have a dictionary o = {d = 3}, what will happen if you print o.d? What about _G.o.d?
  4. Let’s say that you have a list of values {1,2,3,4,5}, what will happen if you do print(unpack({1,2,3,4,5}))? What about print(unpack({1,2,3,4,5,a = 6}))?
  5. Earlier, we talked about how we can mix lists with dictionaries. What will happen if you execute the following code? for i,v in ipairs({1,2,3, a = "haha, I'm ruining everything", 4, 5, 6}) do print(i,v) end
  6. What about {[1] = 1, [2] = 2, [3] = 3}
  7. What about {1,2,3,4,5,[3] = "I'm in your list"}?
  8. Oftentimes, you will see a shorthand for passing lists into functions. Find out what the following does: unpack{1,2,3,4,5} versus unpack({1,2,3,4,5})
  9. While Lua allows you to use tables as keys for dictionaries, this is generally not a good idea. Find out what the following produces:
    dict = {}
    dict[{1,2,3}] = 1
    print(dict[{1,2,3}])

7. Chapter 10: Table Manipulation functions in the Standard Library

This chapter will focus on a few very useful table manipulation functions.

unpack (list, i, j)

Returns the elements from the given table. This function is equivalent to
return list[i], list[i+1], ···, list[j]

Example

list = {1,2,3,4,5,6,7,8,9,10}
print(unpack(list)) -- prints out 1 2 3 4 5 6 7 8 9 10
print(unpack(list, 2)) --prints out 2 3 4 5 6 7 8 9 10
print(unpack(list, 3, 5))--prints out 3 4 5

table.concat (table [, sep [, i [, j]]])

Given an array where all elements are strings or numbers, returns table[i]..sep..table[i+1] ··· sep..table[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is the length of the table. If i is greater than j, returns the empty string.

Example

list = {1,2,"a"}
print(table.concat(list)) -- 12a
print(table.concat(list,", ")) -- 1, 2, a
print(table.concat(list,",", 2)) -- 2,a
print(table.concat(list,"WEE",1,2)) -- 1WEE2

table.insert (table, [pos,] value)

Inserts element value at position pos in table, shifting up other elements to open space, if necessary. The default value for pos is n+1, where n is the length of the table (see §2.5.5), so that a call table.insert(t,x) inserts x at the end of table t.

Example

list = {1,2,3}
table.insert(list,4) -- list is now {1,2,3,4}
table.insert(list,2,4) -- list is now {1,4,2,3,4}

table.remove (table [, pos])

Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, where n is the length of the table, so that a call table.remove(t) removes the last element of table t.

Example

list = {1,2,3,4,5}
table.remove(list) -- list is now {1,2,3,4}
table.remove(list, 2) -- list is now {1,3,4}

table.sort (table)

Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. If comp is given, then it must be a function that receives two table elements, and returns true when the first is less than the second (so that not comp(a[i+1],a[i]) will be true after the sort). If comp is not given, then the standard Lua operator < is used instead. The sort algorithm is not stable; that is, elements considered equal by the given order may have their relative positions changed by the sort.

Example

list = {5,2,3,6,1}
table.sort(list) -- list is now {1,2,3,5,6}

Additional exercises

  • There are no additional exercises for this module.

Next – problem solving

Posted By Lee

Woosh

  • flood

    @first sentence: i thought tables were the only data structure in lua

    • http://phailed.me/ Phailure

      Both functions and userdata can also serve as composite (referenced) data structures. For example, the following is a dictionary implemented using only functions:


      function make_dict()
          return function() return end
      end

      function insert(dict, item, value)
      return function(_)
      if _ == item then
      return value
      else
      return dict(_)
      end
      end
      end

      function remove(dict, item)
      return function(_)
      if _ == item then return else return dict(_) end
      end
      end

      function map(dict, f)
      return function(_)
      return f(dict(_))
      end
      end

      dict = make_dict()

      dict = insert(dict, "a", "A")
      dict = insert(dict, "b", "B")
      dict = insert(dict, "c", "World")
      dict = remove(dict, "b")
      dict = map(dict, function(h) return "Hello "..(h or "") end)

      print(dict("c"))

      But in most cases, complex structures are created using tables so you’re right in most cases.

  • FN_ LP

    Nice, i love your tuts,t hey are neat and easy to understand.

    • Lulz

      That comment confused me for a while. I read it as ” Nice, I love your TITS…”

  • kenvo

    can you add the answers for these exercises :D

  • http://profiles.google.com/dergottdergrunten Ryan Whited

    Under for loops:

    print(“The average height between these cats is “, sum / #cats

    Is missing the “)” at the end.

    • Lawyeritd6

      Yeah, he does that to test you, I think. Stuff like this happens earlier as well :D

  • deryni

    The iterator for loop construct (which is actually the one the refman calls the “generic construct” as opposed to the “numeric construct”) works with any iterator not “just with tables” as you say in the first sentence of Chapter 8.

  • Waseem shah

    Good for new programmer .

  • Jonathan Chapman

    I don’t see a difference between ipairs() and pairs() using the cats example; they print identical results?

    cats = {10, 11, 12, 8, 100}
    for i, v in ipairs(cats) do print(i, v)end
    for h,j in pairs(cats) do print(h, j)end

    • http://www.facebook.com/christopher.patti Christopher Patti

      I thought the same thing, then I thought “Maybe that’s the point?” but really, I’m just confused on this one :)

      • http://phailed.me/ Phailure

        Actually, you’re right, that was a bad example. It was always taught by people that pairs doesn’t return stuff from a table in any particular order (see this comment on the next function: http://www.lua.org/manual/5.1/manual.html#pdf-next), but it turns out that since 5.0, the implementation of next will always return the numerical indices in order so that pairs will behave exactly the same as ipairs

  • Pingback: Chapters 1–5 → An introduction to Lua. | CodingSnake()

  • Pingback: 26. Tables | coolcodea()

  • KimKat

    Great tutorial I like what you do. Keep it up, Lee!
    I want to know if you could provide some examples on how to create tables using raw Lua aswell it’d help out greatly.

  • Pingback: cloud web service()

  • Pingback: affiliate marketing()

  • ungenannt

    Nice tutorial but this ({) looks confusing. Would be better if you used a different color such as a red bracket instead of keeping it within one.

  • Torben

    Thank you for the article! Could you do one about iterators?

    • http://failboat.me/ Lee

      Of course, I’d be happy to :)

  • Victor Dosev

    This is my single best all time favorite Lua tutorial ever. EVER. Nya!