如何在Lua中获取数组的尾部而不复制它?

我正在使用Lua 5.2,并且为了这个问题的假设,假设表格仅用作数组。

以下是一个返回数组的 _tail_(减去第一个元素的数组)的函数:

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

例如:

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

23, 8

但是,这是通过返回表的新副本实现的。有没有办法避免创建新表格?

我正在寻找等价于C的返回指向下一个元素的指针( t++)。这是可能的吗?

点赞
用户734069
用户734069

我在寻找与 C 语言中返回指向下一个元素的指针 (t++) 等效的方法。这种方法可行吗?

不行。你唯一可能想要这个功能的原因是出于性能考虑。这种特性只存在于低级编程语言中。Lua 是一种脚本语言:性能并不是如此重要,因此不会实现这个功能。

只需像你正在做的那样创建另一个表,或使用table.remove来修改原始表。哪个对你最好就用哪个。记住:大而重要的对象,如表和用户数据,都是通过引用存储在 Lua 中的,而不是通过值。

2012-09-11 15:16:51
用户1442917
用户1442917

Nicol 正确指出无法引用数组的切片,但是还有一种更简单/更短的方法可以实现你想要做的事情:

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}), ", ")) 将打印 23,8

(添加 table.unpack or unpack 使其也适用于 Lua 5.2)

2012-09-11 15:50:48
用户1008957
用户1008957

如已经解释过的那样,通常这是不可能实现的。

但是,使用元表,您可以实现一个tail函数,它可以通过_引用_原始表格而无需复制所有数据来执行您想要的操作。以下对Lua 5.2中的大多数操作有效,但例如对于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
2012-09-11 15:53:51
用户222815
用户222815

prapin的建议是使用元表来呈现序列的视图,这大致是我会做的方式。一个可能有用的抽象是为_segments_定义一个元表,它可以是一个0元函数,返回一个表和一个偏移索引的对 - 我们只使用函数来表示元组。然后我们可以定义一个元表,使得这个函数像一个表一样行为:

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 #t-i 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

通过__index和__newindex元方法,您可以编写诸如f[2]=f[1]+1的代码。

尽管这段(未经测试的)代码不会不断创建一次性的元表,但可能比prapin的代码效率低,因为它将调用thunks(0元函数)以获取它们的内容。但如果您可能有兴趣扩展功能,比如对序列有更一般的视图,我认为这是更灵活的。

2012-09-12 12:21:03
用户6342
用户6342

这是我知道的实现tail()的最好方法。它会创建一个新表,但我认为这是不可避免的。

function tail(list)
    return {select(2, unpack(list))}
end
2013-02-11 11:09:43