In Lua, how to get the tail of an array without copying it?

I am wokring with Lua 5.2, and for the sake of this question, suppose tables are used exclusively as arrays.

Here's the function that returns the tail of the array (array minus its first element):

function tail(t) if # t <= 1 then return nil end local newtable = {} for i, v in ipairs(t) do if i > 1 then table.insert(newtable, v) end end return newtable end 

For instance:

prompt> table.concat (tail ({10, 23, 8}), ",")

23, 8

However, this is achieved by returning a new copy of the table. Is there any way to avoid creating a new table?

I am looking for the C equivalent, returning a pointer to the next element ( t++ ). Is it possible?

+4
source share
5 answers

As already explained, this is usually not possible.

However, using metatables, you can implement the tail function, which does what you want without copying all the data, referring to the original table. The following operations are for most operations in Lua 5.2, but, for example, not for table.concat :

 function tail(t) return setmetatable({}, { __index = function(_, k) return t[k+1] end, __newindex = function(_, k, v) t[k+1] = v end, __len = function(_) return #t-1 end, __ipairs = function(_) return function(_, i) if i+1==#t then return nil end return i+1, t[i+2] end, t, 0 end, __pairs = function(t) return ipairs(t) end, }) end 
+9
source

This is the finest way to implement tail (). He creates a new table, but I do not think that this can be avoided.

 function tail(list) return { select(2, unpack(list)) } end 
+4
source

I am looking for the C equivalent, returning a pointer to the next element (t ++). Is it possible?

No. The only possible reason you may want this is for performance. Such a function is available only in low-level programming languages. Lua is a scripting language: performance is not such a priority that it will be implemented.

Just create another table like you, or use table.remove to change the original. Which is best for you. Remember: large, important objects, such as tables and userdata, are stored by reference in Lua, not by value.

+2
source

Nicole is right that you cannot reference a piece of the array, but there is a simpler / shorter way to do what you want to do:

 function tail(t) local function helper(head, ...) return #{...} > 0 and {...} or nil end return helper((table.unpack or unpack)(t)) end 

print(table.concat(tail({10, 23, 8}), ", ")) then print 23,8 .

(added table.unpack or unpack so that it also works with Lua 5.2)

+2
source

prapin suggestion to use metatables to represent a sequence representation, much like I would do. An abstraction that can help is defining meta-tagging for segments, which can be a 0-ary function that returns a table pair and an offset index - we only use functions here to represent tuples. Then we can define a metatable that makes this function behave like a table:

 do local tail_mt = { __index = function(f, k) local t, i=f(); return t[k+i] end, __newindex = function(f, k, v) local t,i=f(); t[k+1] = v end, __len = function(f) local t,i=f(); return #ti end, __ipairs = function(f) local t,i = f () return function (_, j) if i+j>=#t then return nil else return j+1, t[i+j+1] end end, nil, 0 end, } tail_mt.__pairs = tail_mt.__ipairs -- prapin collapsed this functionality, so I do too function tail (t) if type(t) == "table" then return setmetatable ( function () return t, 1 end, tail_mt ) elseif type(t) == "function" then local t1, i = t () return setmetatable ( function () return t1, i+1 end, tail_mt ) end end end 

With the __index and __newindex metamethods, you can write code, for example f [2] = f [1] +1.

Although this (untested) code does not endlessly create one-time meta tags, it is probably less efficient than prapin's, as it will call thunks (0-ary functions) to get its contents. But if you might be interested in expanding the functionality by, say, having more general views on the sequence, I think that is a little more flexible.

+1
source

Source: https://habr.com/ru/post/1433606/


All Articles