Lua - Reversing a List
In order to reverse a list, we can create a iterator which can return the prev element of the list. Then we can start traversing from the last element in order to iterate list in reverse way and store the result in a different list. See the following code of the reverse iterator function on the list.
-- iterate through the list
local function reverseIterate(self, current)
-- if current is nil
-- set the current as last node
if not current then
current = self.last
-- if current is present
-- set current as current prev
elseif current then
current = current._prev
end
-- return current
return current
end
-- return the iterator
function list:reverseIterator()
return reverseIterate, self, nil
end
We can use list:reverseIterator() function to reverse iterate the list which will return the prev element when invoked in a for loop.
We'll build the list and then add method to insert an element. Finally, using iterate function in a for loop, we'll iterate the list in reverse order.
Step 1: Create List
Create a List with a push method to add an element to the end of the list.
-- List Implementation
list = {}
list.__index = list
-- push an element to the end of the list
function list:push(t)
-- move till last node
if self.last then
self.last._next = t
t._prev = self.last
self.last = t
else
-- set the node as first node
self.first = t
self.last = t
end
-- increment the length of the list
self.length = self.length + 1
end
Step 2: Using setmetatable
modify list behavior when list is called to push elements.
setmetatable(list, { __call = function(_, ...)
local t = setmetatable({ length = 0 }, list)
for _, v in ipairs{...}
do t:push(v)
end
return t
end })
Step 3: Create iterator over list
Create an iterator to navigate through elements of the list.
-- iterate through the list
local function reverseIterate(self, current)
-- if current is nil
-- set the current as last node
if not current then
current = self.last
-- if current is present
-- set current as current prev
elseif current then
current = current._prev
end
-- return current
return current
end
-- return the iterator
function list:reverseIterator()
return reverseIterate, self, nil
end
Step 4: Test Iterations on List
In list, we can insert objects, and test the iteration
l = list({A}, {"B"}, {"C"},"D"},{"E"}, {"F"} )
-- iterate throgh entries
for v in l:reverseIterator() do
print(v[1])
end
Complete Example - Reversing elements of a List
Following is the complete example of inserting and reversing elements of a list and storing them in a table.
main.lua
-- List Implementation
list = {}
list.__index = list
setmetatable(list, { __call = function(_, ...)
local t = setmetatable({ length = 0 }, list)
for _, v in ipairs{...}
do t:push(v)
end
return t
end })
-- push an element to the end of the list
function list:push(t)
-- move till last node
if self.last then
self.last._next = t
t._prev = self.last
self.last = t
else
-- set the node as first node
self.first = t
self.last = t
end
-- increment the length of the list
self.length = self.length + 1
end
-- iterate through the list
local function reverseIterate(self, current)
-- if current is nil
-- set the current as last node
if not current then
current = self.last
-- if current is present
-- set current as current prev
elseif current then
current = current._prev
end
-- return current
return current
end
-- return the iterator
function list:reverseIterator()
return reverseIterate, self, nil
end
-- create a new list with values
local l = list({ "Mon" }, { "Tue" }, { "Wed" }, { "Thu" }, { "Fri" })
local reversedList = {}
local index = 1
-- iterate throgh entries in reverse order
for v in l:reverseIterator() do
reversedList[index] = v[1]
index = index + 1
end
-- print the reversed entries
for _,v in ipairs(reversedList) do
print(v)
end
Output
When we run the above code, we will get the following output−
Fri Thu Wed Tue Mon