Search code examples
lualua-table

Iterate through a complex Lua table and delete table values until a specified text is found


This is perplexing me, and I won't be surprised if there is an answer for it already. I just haven't found it. I have a table that looks like this:

lines = {
  { 
    { text = "Some Random Text" } 
  },
  { 
    { text = "~~~~~~~~" },
    { text = "Some more text" } 
  },
  { 
    { text = "~~~~~~~~" } 
  },
  { 
    { text = "Some extra text" } 
  }
}

What I'm needing to do is iterate through the 'lines' table and remove every index before the index that contains the first "~~~~~~~~", and every index after the very last "~~~~~~~~". The table above is simple; however, it can have several lines of "~~~~~~~~" mixed in.

The resulting return should only be:

lines = {
  { 
    { text = "~~~~~~~~" },
    { text = "Some more text" } 
  },
  { 
    { text = "~~~~~~~~" } 
  }
}

I'm at a loss, though. Every solution I've tried has failed, and I'm not sure what I'm missing. My most recent attempt is:

function findBoundaries(tbl)
   local foundStart = false
   local tildeStr = string.rep("~", 79)
   for i,v in ipairs(tbl) do
      if v[1].text == tildeStr then
         foundStart = true
         break
      else
         table.remove(tbl, i)
      end
   end
   if foundStart then
      for i = #tbl, 1, -1 do
         if tbl[i][1].text == tildeStr then
            break
         else
            table.remove(tbl, i)
         end
      end
   end
   return tbl
end

What is the most efficient way to return the results I'm needing?


Solution

  • Invoking table.remove() for one array element at a time is not efficient.
    Try to find the "table center" (the range between two tildas) and then move it to the beginning of the array in a single call to table.move.

    -- assuming you have Lua 5.3+
    function findBoundaries(tbl)
       local tildeStr = string.rep("~", 79)
       for indexStart,v in ipairs(tbl) do
          if v[1].text == tildeStr then
             for indexEnd = #tbl, 1, -1 do
                if tbl[indexEnd][1].text == tildeStr then
                   table.move(tbl, indexStart, indexEnd, 1)
                   local len = indexEnd - indexStart + 1
                   table.move(tbl, #tbl + 1, #tbl*2 - len, len + 1)
                   return tbl
                end
             end
          end
       end
       return tbl
    end