paint-brush
Lua Tables: Techniques for Maintaining and Sorting Order in Arrays and Dictionariesby@volodymyrkozub85
115 reads

Lua Tables: Techniques for Maintaining and Sorting Order in Arrays and Dictionaries

by VladimirSeptember 9th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

This guide explores Lua's table functionalities, including maintaining insertion order, converting Redis results, and sorting tables by keys or values. It provides practical examples for handling arrays and dictionaries in Lua.
featured image - Lua Tables: Techniques for Maintaining and Sorting Order in Arrays and Dictionaries
Vladimir HackerNoon profile picture

Lua is a highly versatile programming language. It is widely used in gaming, embedded systems, web development, networking, automation, and customization. Its small size, flexibility, and speed make it a great choice for embedding into larger applications or for use in environments with constrained resources.


When using Lua, we can’t avoid tables. Lua tables are flexible and can be used as arrays, dictionaries (hash maps), or even mixed structures. Tables have no fixed size and can grow based on our needs.


Meanwhile, there is one important thing we should not forget: ordering in tables.

Order insertion in tables

Lua tables, when used as arrays, maintain the insertion order, which makes them a good candidate for lists or arrays in various use cases, including with Redis.


In this case, tables can be created manually in the script or returned as a result by third-party libraries, like Redis.


Let’s create the table manually and check the insertion order:

steps = {}
for i = 1, 10, 1 do
    table.insert(steps,i)
end

After the loop, steps = {1; 2; 3; 4; 5; 6; 7; 8; 9; 10}


Let’s check what happens when Redis returns a table as a result.

redis.call("HSET", 'users', 345, "John", 122, "Bob", 543, "Sam")
local dataDb = redis.call("HGETALL", 'users')

After the script is executed, dataDb = {"345", "John", "122", "Bob", "543", "Sam"}


In both scenarios, we can find the created table as an array where the insertion order is preserved.


But what if we need to convert the Redis response (which is a table as an array) into a key-value associative array?

For the first example, we store the following key-value pairs in Redis and want to use the same structure in Lua when processing:

{
     345: {name: “John”},
     122: {name: “Bob”},
     543: {name: “Sam”},
     202: {name: “Peter”}
}


Run the following script and check the created associative array:

redis.call("HSET", 'users', 345, "John", 122, "Bob", 543, "Sam", 202, "Peter")
 
local dataDb = redis.call("HGETALL", 'users')
 
local directory = {}
 
for i = 1, #dataDb, 2 do
    directory[dataDb[i]] = dataDb[i+1]
end

where, after the loop

dataDb = {"345"; "John"; "122"; "Bob"; "543"; "Sam"; "202"; "Peter"}

directory = {["122"]="Bob"; ["345"]="John"; ["202"]="Peter"; ["543"]="Sam"}


Let's look at another example of using the cjson module:

redis.call('SET', 'packages', '{"10":{"name":"Plus"},"15":{"name":"Family"},"25":{"name":"Premium"}}')
 
local pkgsDb = redis.call('GET', 'packages')
local parsedPkgs = cjson.decode(pkgsDb)

where:

pkgsDb = "{\"10\":{\"name\":\"Plus\"},\"15\":{\"name\":\"Family\"},\"25\":{\"name\":\"Premium\"}}"

parsedPkgs = {["25"]={["name"]="Premium"}; ["15"]={["name"]="Family"}; ["10"]={["name"]="Plus"}}


It is good to remember that the CJSON module returns a table in a different order than the one parsed in the JSON. This can prevent errors and save you time, as debugging such problems is quite difficult.


In both scenarios, we may find that the insertion order is not guaranteed in a table as an associative array.


How to sort a table key when needed?

Sometimes, having ordered tables in Lua is important. The order of elements can be critical for the functionality that the script provides.

We can use the built-in table.sort function to sort tables. It receives the array to be sorted, along with an optional order function. If this function is not provided, sort uses the default mode. All numeric values will be sorted in ascending order, and all strings will be sorted alphabetically.

Sorting table – array

In the case of simple sorting of numeric or string values, it is enough to use the following expression:

local num = {4, 2, 6}
local str = {"pear" ,"apple", "melon"}
 
table.sort(num)
table.sort(str)

where sorted  num = {2; 4; 6} and str = {"apple"; "melon"; "pear"}


If the sorting is based on a certain condition, we can define a comparison function.

local t = {4,7,2,3}
table.sort(t, function(a, b) return a > b end)

where sorted   t = {4; 7; 2; 3}

Sorting a table – dictionary

To sort a table structured as a dictionary, we can sort it by key or value. This requires several steps:

  1. Extract the keys or values into an array-like table

  2. Sort this array

  3. Iterate over the sorted keys and get the value from the original array by key


Sort by keys:

local transport = {[100]="train", [70]="tram", [90]="bus"}
 
local keys = {}
for key in pairs(transport) do
    table.insert(keys, key)
end
 
table.sort(keys)
 
for _, key in ipairs(keys) do
    print(key, transport[key])
end

Script result: 70 tram, 90 bus, 100 train


Sort by values:

local entities = {}
 
for key, value in pairs(transport) do
    table.insert(entities, {key = key, value = value})
end
 
table.sort(entities, function(a, b) return a.value < b.value end)
 
for _, entity in ipairs(entities) do
    print(entity.key, entity.value)
end

Script result: 90 bus, 100 train, 70 tram


Conclusion

Having ordered tables in Lua is important when the order of elements matters. In Lua, tables that function like dictionaries have no inherent order, meaning that when we iterate over them using pairs(), the order of elements is not guaranteed. In this article, we explored how to sort arrays in Lua using table.sort and how to manage separate key and value arrays for sorting dictionaries.