Lua - Chaining Iterator



Lua is not having built-in support for chaining iterators. But we can create our own chaining iterator by table manipulations. Goal of this chain iterator is to iterate multiple iterables sequentially as they are single iterable. In this chapter, we'll discuss various options to create a chaining iterator with examples.

Example - Create a Custom Chaining Iterator

We're creating a function which can take multiple iterables represented by tables and it will return a single iterator which iterates through each iterables one by one and we'll print each values.

main.lua

-- function representing chain iterator
function chainIterator(...)
   local iterables = {...}
   local iterable_index = 1
   local index = 1

   return function()
      while iterable_index <= #iterables do
         local iterable = iterables[iterable_index]
         if type(iterable) ~= "table" then  -- if argument is not a table
            error("Invalid input. Only table can be passed.")
         end
		 -- iterate through table entries
         if index <= #iterable then
            local value = iterable[index]
            index = index + 1
            return value
         else -- go to next table
            iterable_index = iterable_index + 1
            index = 1 -- Reset index for the next table
         end
      end
      return -- end of iteration
   end
end

local list1 = {1, 2, 3, 4}
local list2 = {'a', 'b', 'c'}
local list3 = {10, 20}

for item in chainIterator(list1, list2, list3) do
   print(item)
end

Output

When the above code is built and executed, it produces the following result −

1
2
3
4
a
b
c
10
20

Explanation

  • chainIterator(...) function takes variable arguments as tables and stored in itearable table.

  • iterable_index is to track current table and index is to track current item of a table.

  • Using return function() we've returned an anonymous function which acts as an iterator to give the next item.

  • while iterable_index <= #iterables do loop is to iterate all tables.

  • if index <= #iterable then is used to return item of current iterable. Once current iterable is done, we're moving to next iterable.

Example - Chaining into a New Table

Instead of creating a chaining iterator, we can combine tables as well as shown in example below −

main.lua

function combineTables(...)
   local result = {}
   -- iterate through each table
   for i = 1, select('#', ...) do
      -- get the iterator
      local iterable = select(i, ...)
      if type(iterable) ~= "table" then
         error("Invalid input. Only table can be passed.")
      end
	  -- iterate through table values and insert into result table
      for _, value in ipairs(iterable) do
         table.insert(result, value)
      end
   end
   -- return the combined table
   return result
end

local list1 = {1, 2, 3, 4}
local list2 = {'a', 'b', 'c'}
local list3 = {10, 20}

local combinedList = combineTables(list1, list2, list3)

for _,item in ipairs(combinedList) do
   print(item)
end

Output

When the above code is built and executed, it produces the following result −

1
2
3
4
a
b
c
10
20

Explanation

  • combineTables(...) function takes variable arguments as tables and returns a combined table of all values of the table passed.

  • result represents the combined table. Using for loop, we're navigating through each table.

  • Using ipairs, we're iterating each element of the input table and values are inserted to combined table as result.

  • Finally result is returned.

Advertisements