unknown_document

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


Modifying Lua Maps
Maps can be modified after they are created. Starting from the following map : local x = { a = 1 , b = 2 , c = 3 , d = 4 , } let's look at modifying existing values in the map . As a saw in the previous section we can access elements in the map by retrieving the key from the map , and also by accessing each key as a property of the map . We can also use either method to assign values to the map : -- update a value in the table by key x [ "b" ] = 9 -- update value by property x . c = 11 print ( x [ "a" ]) -- 1 print ( x [ "b" ]) -- 9 print ( x [ "c" ]) -- 11 print ( x [ "d" ]) -- 4 Inserting a value is works the same way: we simply create a new key by assigning a value to it: -- insert a value in the table x [ "e" ] = 5 x . f = 6 print ( x [ "a" ]) -- 1 print ( x [ "b" ]) -- 9 print ( x [ "c" ]) -- 11 print ( x [ "d" ]) -- 4 print ( x [ "e" ]) -- 5 print ( x [ "f" ]) -- 6 Removing a value from the map is done by assigning nil to it: -- remove an item from the map x . e = nil print ( x [ "a" ]) -- 1 print ( x [ "b" ]) -- 9 print ( x [ "c" ]) -- 11 print ( x [ "d" ]) -- 4 print ( x [ "e" ]) -- nil print ( x [ "f" ]) -- 6
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.
Creating Lua Maps
Maps , often also called Dictionaries and associative arrays , are data structures that organize elements such that each element can be easily retrieved by its name, or key. Unlike lists maps do not guarantee fixed ordering, values can be assigned to maps in any order, and retrieved in any order. A map is created by instantiating a table of values, as below: -- initialize a mapping of key, value pairs local x = { a = 1 , b = 2 , c = 3 , d = 4 , } Let's try printing the map : print ( x ) -- table: 0x59b68bdd9de0 As we saw in lists , 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 map requires accessing them individually. -- access values stored in the table print ( x [ "a" ]) -- 1 print ( x [ "b" ]) -- 2 print ( x [ "c" ]) -- 3 print ( x [ "d" ]) -- 4 -- accessing values *not* in the table returns nil print ( x [ "x" ]) -- nil Lua also allows map values to be accessed by referencing map keys as properties: -- access values stored in the table print ( x . a ) -- 1 print ( x . b ) -- 2 print ( x . c ) -- 3 print ( x . d ) -- 4 -- accessing values *not* in the table returns nil print ( x . x ) -- nil There is a second method for creating maps , which is often helpful when creating maps programmatically such as in a loop . In this this method, an empty map is created and assigned to a variable , then values are assigned directly to each key: -- initialize an empty table local x = {} -- assign values to each key x [ "a" ] = 1 x [ "b" ] = 2 x [ "c" ] = 3 x [ "d" ] = 4 After the map is created, its elements can be accessed as usual: -- access values stored in the table print ( x [ "a" ]) -- 1 print ( x [ "b" ]) -- 2 print ( x . c ) -- 3 print ( x . d ) -- 4
Length of Lua Maps
We discussed Lua's length operator in the context of lists and strings . Now let's take a look at finding the length of a map . Let's first take a look at how the length operator behaves with a map : local x = { a = 1 , b = 2 , c = 3 , d = 4 , e = 5 , } print ( # x ) -- 0 Hmm, that was not expected. The table clearly has 5 values in it, but the result is 0. It turns out the that length operator only considers the number of list-like values contained in a table, and does not consider mappings at all. Getting the number of items in a map requires counting items manually: local count = 0 for key , val in pairs ( x ) do count = count + 1 end print ( count ) -- 5
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 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
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.
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
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
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.