unknown_document

We couldn't find that page... Were you looking for one of these?


Iterating Lists in Lua
Iterating over the elements of a list is a very common operation. Known Length Lists If the number of elements in the list is known, then it is easy to iterate over the elements using a simple numeric for loop: local x = { "a" , "b" , "c" , "d" } for i = 1 , 4 do print ( i .. ": " .. x [ i ]) end which produces the result: 1: a 2: b 3: c 4: d This can also be used to iterate over list that contain nil values, which (as we will see in a moment) can be problematic when iterating over lists using other methods. Note that because the concatenation operator will not allow a nil value we have to test for nil and replace it with a string "nil": local x = { "a" , "b" , nil , "c" , "d" } for i = 1 , 5 do print ( i .. ": " .. ( x [ i ] or "nil" )) end which produces the output: 1: a 2: b 3: nil 4: c 5: d Unknown Length Lists When the length of the list is not known we can use the generic for to iterator over the items in the list . There are two built-in iterator functions , pairs and ipairs . Let's first look at iterating lists using pairs : pairs The pairs function returns an iterator over key, value pairs from the list . Due to the way that lists are created with tables , the keys are the indices of each element of the list , while the values are the element values themselves. Let's take a look: local x = { "a" , "b" , "c" , "d" } for i , v in pairs ( x ) do print ( i .. ": " .. v ) end which produces the output: 1: a 2: b 3: c 4: d Let's compare that to the other built-in iterator function, ipairs : ipairs The ipairs iterator function creates a counter and iterates over the elements of the list , yielding index, value pairs. Due to the way that lists are created with tables , this produces the same output that we just saw with pairs : local x = { "a" , "b" , "c" , "d" } for i , v in ipairs ( x ) do print ( i .. ": " .. v ) end with the output: 1: a 2: b 3: c 4: d While both iterator functions produced the same output, they behave quite differently when there are nil values in the lists : Careful! Be careful when there are nil values in the list , as the results can be a bit unexpected and surprising. using pairs with nil values Let's first look at how the pairs function behaves when there are nil values in the list : local x = { "a" , "b" , nil , "c" , "d" } for i , v in pairs ( x ) do print ( i .. ": " .. v ) end with the result: 1: a 2: b 4: c 5: d Although there are five elements in the list , the pairs function only yields four of them, silently skipping the nil element. While this can be a helpful feature, in some cases we will want to know if there are nil values in the list and this behavior would prevent that. Now let's see how the ipairs function behaves: using ipairs with nil values Here we look at the same input again, but with the ipairs function: local x = { "a" , "b" , nil , "c" , "d" } for i , v in ipairs ( x ) do print ( i .. ": " .. v ) end which produces somewhat different results: 1: a 2: b Rather than iterating over each item in the list , the ipairs function simply stopped iterating elements when it reached the first nil value. This is rarely expected behavior, and can lead to some unexpected behavior. We can learn more about this behavior by examining how the length operator behaves with lists , in the next section.
Creating Lists in Lua
Lists , often also called arrays , are data structures that organize elements such as values by index. A list is created by instantiating a table of values, as below: -- initialize a table with values local x = { "a" , "b" , "c" } Let's try printing the list : print ( x ) -- table: 0x6121ee19eda0 By default, when Lua prints a table it displays the type (table) followed by its address in memory, which can be useful in some situations but generally isn't what we want. Inspecting the values of a list requires accessing them individually. -- access values stored in the table print ( x [ 1 ]) -- a print ( x [ 2 ]) -- b print ( x [ 3 ]) -- c -- accessing values *not* in the table returns nil print ( x [ 9 ]) -- nil There is a second method for creating lists , which is often helpful when creating lists programmatically such as in a loop . In this this method, an empty list is created and assigned to a variable , then values are assigned directly by index: -- initialize an empty table local x = {} -- assign values by index x [ 1 ] = "d" x [ 2 ] = "e" x [ 3 ] = "f" After the list is created, its elements can be accessed as usual: -- access values stored in the table print ( x [ 1 ]) -- d print ( x [ 2 ]) -- e print ( x [ 3 ]) -- f A variation on this method uses the table.insert method to append values to the list , and will be discussed shortly .
Sorting Lists in Lua
One very common operation on lists is sorting them. Lua's table library contains the table.sort function local x = { "b" , "e" , "a" , "d" , "c" , } Default Sort -- list is sorted in-place table.sort ( x ) print ( x [ 1 ]) -- a print ( x [ 2 ]) -- b print ( x [ 3 ]) -- c print ( x [ 4 ]) -- d print ( x [ 5 ]) -- e Sorting in Reverse -- list is sorted in-place table.sort ( x , function ( a , b ) return a > b end ) print ( x [ 1 ]) -- e print ( x [ 2 ]) -- d print ( x [ 3 ]) -- c print ( x [ 4 ]) -- b print ( x [ 5 ]) -- a Random Order local math = require ( "math" ) -- list is sorted in-place table.sort ( x , function ( a , b ) return math.random () > 0.5 end ) print ( x [ 1 ]) -- d print ( x [ 2 ]) -- a print ( x [ 3 ]) -- b print ( x [ 4 ]) -- c print ( x [ 5 ]) -- e
Lua List Length
Lua includes a length operator # which (in theory) returns the number of items contained in the value to which it is applied. However, it is frankly a bit wonky and can give unexpected results if used outside of a fairly narrow range of applications. Let's take a look: We learned earlier than tables are collections of values. It can often be helpful to know how many values are contained in a collection. Let's look a list-like tables first: Lists Let's create a list then see how many items are in it: local x = { 1 , 2 , 3 , 5 , 6 } print ( # x ) -- 5 Ok, that worked as we might expect. Five values we added to the list, and the length operator returned a length of 5. Let's see what happens with a list of nil values: local y = { nil , nil } print ( # y ) -- 0 Hmm, the list contains 2 nil values, but returns a length of 0. Should we have expected a length of 0 or a length of 2? On one hand there are 2 nil values in the list, but on the other hand nil is considered to be "not a value". Let's leave that debate to the philosophers, the important thing for programmers is that Lua has an opinion about this, and applies that opinion consistently. So, based on this result we can conclude that Lua does not count nil values in lists. Let's look at another example: local x = { 1 , 2 , 3 , nil , 4 , 5 } print ( # x ) -- 6 Er, hold on. Lua counted nil as a value this time? It turns out that the process Lua uses to calculate the length of list-like tables is not as simple as counting values in the list, and gets complicated when the list contains nil values. Even worse, the result that is returned depends not only on the values that are in the list at the time that the length operator is applied, it depends on how the table was created and populated. Let's see what happens when we build this table another way: local y = {} y [ 1 ] = 1 y [ 2 ] = 2 y [ 3 ] = 3 y [ 4 ] = nil y [ 5 ] = 4 y [ 6 ] = 5 print ( # y ) -- 3 Although these tables contain the same values, this table has a length of 3? After digging through the Lua documentation to gain a better understanding of how this operator works, we have learned that the situation is even worse than expected - this example could have returned any of 2, 3, 5, or 6. So, while the length operator can be useful with list-like tables, care must be taken to ensure that the lists it operates don't contain any nil values.
Modifying Lua Lists
Lists can be modified in various after they are created. Starting from our original list : local x = { "a" , "b" , "c" } We can modify values in the list by assigning values to an index: -- update a value in the table x [ 2 ] = "x" print ( x [ 1 ]) -- a print ( x [ 2 ]) -- x print ( x [ 3 ]) -- c We can insert values using the table.insert function: -- add a value to the end of the table table.insert ( x , "d" ) print ( x [ 1 ]) -- a print ( x [ 2 ]) -- x print ( x [ 3 ]) -- c print ( x [ 4 ]) -- d -- add a value to the end of the table table.insert ( x , 2 , "y" ) print ( x [ 1 ]) -- a print ( x [ 2 ]) -- y print ( x [ 3 ]) -- x print ( x [ 4 ]) -- c print ( x [ 5 ]) -- d Likewise, we can also remove items using the table.remove function: -- remove a value from the table table.remove ( x , 2 ) print ( x [ 1 ]) -- a print ( x [ 2 ]) -- d print ( x [ 3 ]) -- nil
Multi-dimensional Lists in Lua
Since lists can contain any type as elements, they can also contain other lists . This allows multi-dimensional lists , sometimes called "matrices", to be created. A multi-dimensional list can be created directly as before: -- initialize a table with values local x = { { "a" , "b" , "c" }, { "d" , "e" , "f" }, { "g" , "h" , "i" }, } Now, when we access the direct descendants of this list we get the nested list . We can access the nested elements themselves by indexing the nested lists : -- access values stored in the table print ( x [ 1 ]) -- table: 0x5e35821553e0 print ( x [ 1 ][ 1 ]) -- a print ( x [ 1 ][ 2 ]) -- b print ( x [ 1 ][ 3 ]) -- c We can also create multi-dimensional lists programmatically as well. In this example we create the list and add elements in a loop : -- initialize an empty list local x = {} for i = 1 , 3 do -- instantiate an empty list to contain the nested content local inner = {} for j = 1 , 3 do inner [ j ] = string.char ( 97 + 3 * ( i - 1 ) + ( j - 1 )) end x [ i ] = inner end This makes use of the string.char function to generate characters from their decimal ASCII codes. After the list is created, its elements can be accessed as usual: -- access values stored in the table print ( x [ 1 ][ 1 ]) -- a print ( x [ 1 ][ 2 ]) -- b print ( x [ 1 ][ 3 ]) -- c print ( x [ 2 ][ 1 ]) -- d print ( x [ 2 ][ 2 ]) -- e print ( x [ 2 ][ 3 ]) -- f print ( x [ 3 ][ 1 ]) -- g print ( x [ 3 ][ 2 ]) -- h print ( x [ 3 ][ 3 ]) -- i
Lua Tables as String Buffers
As with most programming languages, Lua strings are immutable , meaning that they cannot be modified after they are created. Changing a string requires creating a new string that consists of the characters of the previous string, plus whatever changes are made to it. While simple concatenation is fine for small changes, creating a new string for every change becomes very inefficient for larger changes and should be avoided when possible. One way to overcome this inefficiency is the string buffer , which offers a more efficient means of "composing" strings from many smaller strings. String buffers are implemented in Lua using tables , and more specifically they are an application of lists . This means that all of the topics discussed in the lists section apply to string buffers , and this section will focus only on the string buffer application. Let's jump right into an example, starting with the following list of strings . Implementing a string buffer involves creating a list , populating it with each component string , then finally compiling the final string using the table.concat function. Let's demonstrate using the following list : local x = { "this" , "is" , "a" , "string" , } then concatenate the list into the final string : print ( table.concat ( x , " " )) -- this is a string Note that each sub-string is separated by a space, which was passed to the table.concat function. We could have passed another separator, such as a - : print ( table.concat ( x , "-" )) -- this-is-a-string That's about all it takes. Of course, compiling the list will generally be more complicated than this example, and will involve one of more of the methods discussed in the list section, but once the list is populated this is all it takes.
Lua Tables
Lua implements a single data structure , which is implemented as a general-purpose collection that encompasses functionality that is usually implemented by several different data structures in other programming languages. This makes tables powerful, but can also make it a bit challenging to work with, and can lead to surprising results if one is not careful. For example, while tables can act as both lists and mappings , most table functions generally make an assumption about how the table is being used. When a table function is used in the wrong context it won't generate an error, it will just return an unexpected result. We find it helpful to think of the table as a Swiss Army Knife ; it can support many functions, but in order to complete a task you have to first determine the role you want the knife to perform, then use the knife in a way that is consistent with that role. For example, if the goal is to open a bottle, then the knife plays the role of a bottle opener. The bottle-opener tool must be selected, and the knife must be used like a bottle-opener. It would be difficult to open a bottle with the toothpick or magnifying glass tools, even if they are used like a bottle-opener. Likewise, it would be equally difficult to open a bottle with the bottle-opener tool if it were to be used like a toothpick or a magnifying glass. With this in mind, rather than discuss tables as a single, all-encompassing data structure, we will identify the role that we want the table to perform, then discuss how to use the tables in that role. Of the many different roles a table can perform, we currently focus on the most common: Lists (also called Arrays) Maps (also called Dictionaries or Associative Arrays) String Buffers
Lua
Lua is a lightweight, cross-platform, high-level programming language that has become increasingly-popular as an embedded scripting language. Lua is often praised as a clean, simple, easy to learn scripting language that is applicable to a wide range of tasks. Today Lua can be found in a wide range of applications ranging from wezterm to xplr and neovim . Let's get started.
Iterating Over Lua Maps
Iterating over a map done via the pairs function, which produces key, value pairs for each element in the map . Starting from the following map : local x = { a = 1 , b = 2 , c = 3 , d = 4 , e = 5 , } we can see how this operates using the following loop : for key , value in pairs ( x ) do print ( key .. ": " .. value ) end which produces the following output: e: 5 d: 4 c: 3 b: 2 a: 1 Note that the order of the output is different than that of the input. Unlike lists , maps do not maintain the order of entries, or have any sense of order at all. In fact, if we iterate over the map again we should expect to process the elements in a different order: e: 5 a: 1 b: 2 c: 3 d: 4 Keep this in mind when iterating over maps . When we looked at iterating lists that nil values can create some surprising behaviors. Let's take a quick look at iterating over maps that contain nil values: x . c = nil for key , value in pairs ( x ) do print ( key .. ": " .. value ) end which produces the result: d: 4 e: 5 b: 2 a: 1 As we saw in modifying , setting a map value to nil simply removes the key-value pair from the map . As a result, iterating over a map using pairs behaves as expected.