![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
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.
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.
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.
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}
To sort a table structured as a dictionary, we can sort it by key or value. This requires several steps:
Extract the keys or values into an array-like table
Sort this array
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
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.