Lua - Functional Operations on Lists



Functional Programming refers to a declarative programming model where the focus is on "What you are doing" instead of "How you are doing". In Lua, we can functional programming easily on lists by making custom codes. Following are few examples of commonly used functional programming constructs.

  • map− applies a given function on each element of the list and returns a table with updated values.

  • apply− applies a given function on each element of the list and updates its each value.

  • filter− filter element of the list based on given function and returns a table with filtered values.

  • concat− concatenate elements of each list

  • reverse−reverses the elements of the list

  • sort−sorts the elements of the list

Let's explore few functions by examples.

map function

Consider a case, where we've having a List of numbers and we want to get a table of squares of these numbers. Following implementation of map function will help in achieving the same.

-- map function to apply a function on a list
function map(f, list)
   local squares = {}
   -- get result of function on each element
   -- and store in a table
   for v in list:iterator() do 
      table.insert(squares, f(v[1]))
   end
   -- return the resulant table
   return squares
end

Complete Example of Applying map function on a list

In following example, we'll apply the map function to get squares of each number of a list.

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

-- map function to apply a function on a list
function map(f, list)
   local squares = {}
   -- get result of function on each element
   -- and store in a table
   for v in list:iterator() do 
      table.insert(squares, f(v[1]))
   end
   -- return the resulant table
   return squares
end

-- create a new list with values
local numbers = list({ 1 },{ 2 }, { 3 },{ 4 },{ 5 })

squares = map(function(n) return n*n end, numbers)

-- list of squares
for _,v in ipairs(squares) do
   print(v) 
end

Output

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

1
4
9
16
25

apply function

Consider a case, where we've having a List of numbers and we want to update them to be squares of these numbers. Following implementation of apply function will help in achieving the same.

-- apply function to apply a function on a list
function apply(f, list)
   -- apply function on each element
   -- and update the value
   for v in list:iterator() do 
      v[1] = f(v[1])
   end
end

Complete Example of Applying apply function on a list

In following example, we'll use the apply function to make squares of each number of a list.

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

-- apply function to apply a function on a list
function apply(f, list)
   -- apply function on each element
   -- and update the value
   for v in list:iterator() do 
      v[1] = f(v[1])
   end
end

-- create a new list with values
local numbers = list({ 1 },{ 2 }, { 3 },{ 4 },{ 5 })

squares = apply(function(n) return n*n end, numbers)

-- list of squares
for v in numbers:iterator() do 
 print(v[1])
end

Output

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

1
4
9
16
25

In the similar fashion, we can create any functional program over Lua list as shown in examples above.

Advertisements