Lua - Slicing Lists



In Lua, there is no inbuild support for slicing array/table but using table.unpack() function, we can achieve the same. And using the same technique we can slice a linked list as well. We'll be using inbuilt function table.unpack() which accepts an array and gives the sliced array. We need to convert the linked list to an array, get the sliced array using table.unpack() and then rebuild the linked list from the sliced array as shown in steps below:

Get an Array from the List

Iterate through each entry of the list and store each value into the array.

-- convert list to an array
function list:toArray()
   local array = {}

   local current = self.first

   while current do
      table.insert(array, current[1])
      current = current._next
   end

   return array
end

Slice the array using table.unpack() function

-- get array from the list
local arr = l:toArray()

-- unpack the array with start/end indexes
local slicedArray = {table.unpack(arr, 2, 4)}

Rebuild the list using sliced array

-- create a new list
l = list()

-- push the slicedArray entries into the list
for _, v in ipairs(slicedArray) do
   l:push({v})
end

Complete Example - Slicing the linked List

In below example, we're slicing the linked list using above steps. We created a linked list of 6 values and then sliced it from 2nd to 4th value.

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 iterate(self, current)
   if not current then
      current = self.first
   elseif current then
      current = current._next
   end
  
   return current
end

function list:iterator()
   return iterate, self, nil
end

-- convert list to an array
function list:toArray()
   local array = {}
    
   local current = self.first

   while current do
      table.insert(array, current[1])
      current = current._next
   end
    
   return array
end

-- create a new list with values
local l = list({ "A" },{ "B" }, { "C" },{ "D" } , { "E" }, { "F" })

print("Original List")
-- iterate throgh entries
for v in l:iterator() do 
   print(v[1]) 
end

-- get array from the list
local arr = l:toArray()

-- unpack the array with start/end indexes
local slicedArray = {table.unpack(arr, 2, 4)}

-- create a new list
l = list()

-- push the sliced entries into the list
for _, v in ipairs(slicedArray) do
   l:push({v})
end

-- print the sliced list
print("Sliced List")
-- iterate throgh entries
for v in l:iterator() do 
   print(v[1]) 
end

Output

When we run the above code, we will get the following output−

Original List
A
B
C
D
E
F
Sliced List
B
C
D
Advertisements