Lua 列表怎么删除元素?

文章导读
Previous Quiz Next 从链表中移除一个元素需要更新要移除元素的 prev node 和 next node 的引用。
📋 目录
  1. 最后一个元素的情况
  2. 其他元素的情况,t
  3. 步骤 1: 创建 List
  4. 步骤 2: 使用 setmetatable
  5. 步骤 3: 创建链表迭代器
  6. 步骤 4:创建 removeLast() 和 remove() 方法
  7. 步骤 5:在 List 上测试移除操作
  8. 完整示例 - 从列表中移除元素
A A

Lua - 从 List 中移除元素



Previous
Quiz
Next

从链表中移除一个元素需要更新要移除元素的 prev node 和 next node 的引用。

最后一个元素的情况

我们可以将 prev node 的 next 设置为 nil,并将 last 设置为 prev node,如以下伪代码所示——

-- 获取最后一个节点
local removedElement = self.last
  
-- 如果存在 prev
-- 则将 prev 节点设置为最后一个节点  
if removedElement._prev then
  removedElement._prev._next = nil
  self.last = removedElement._prev
  removedElement._prev = nil
else
  -- 最后一个节点是链表中唯一的节点
  self.first = nil
  self.last = nil
end

其他元素的情况,t

如果 t 同时具有 next 和 prev 节点,则更新 t.next 和 t.prev 的 prev 和 next 引用。如果 t 是第一个节点,则将 first 设置为 t.next。

查看以下伪代码——

if t._next then
   if t._prev then
      t._next._prev = t._prev
      t._prev._next = t._next
   else
      -- 这是第一个节点
      t._next._prev = nil
      self._first = t._next
   end
elseif t._prev then  -- 如果节点只有 prev 节点
   -- 这是最后一个节点
   t._prev._next = nil
   self._last = t._prev
else
   -- 这是唯一的节点
   self._first = nil
   self._last = nil
end

现在我们将逐步构建链表,添加从链表末尾移除元素的方法以及从链表中移除特定元素的方法,如下所示:

步骤 1: 创建 List

创建一个带有 push 方法的 List,用于向链表末尾添加元素。

-- List 实现
list = {}
list.__index = list

-- 将元素推入链表末尾
function list:push(t)
   -- 移动到最后一个节点    
   if self.last then
      self.last._next = t
      t._prev = self.last
      self.last = t
   else
      -- 将节点设置为第一个节点
      self.first = t
      self.last = t
   end
   -- 递增链表长度
   self.length = self.length + 1
end

步骤 2: 使用 setmetatable

修改 list 的行为,当调用 list 来推送元素时。

setmetatable(list, { __call = function(_, ...)
   local t = setmetatable({ length = 0 }, list)
      for _, v in ipairs{...} 
         do t:push(v) 
      end
      return t
   end })

步骤 3: 创建链表迭代器

创建一个迭代器来遍历链表中的元素。

-- 遍历链表
local function iterate(self, current)
   if not current then
      current = self.first
   elseif current then
      current = current._next
   end
  
   return current
end

function list:iterate()
   return iterate, self, nil
end

步骤 4:创建 removeLast() 和 remove() 方法

创建 removeLast() 以从列表末尾移除元素,以及 remove(t) 以移除指定的元素。

-- 从列表中移除最后一个元素
function list:removeLast()
   -- 如果 last 为 nil 则返回
   if not self.last then
      return 
   end
   local removedElement = self.last
  
   -- 如果存在 prev
   -- 则将 prev 节点设置为最后一个节点  
   if removedElement._prev then
      removedElement._prev._next = nil
      self.last = removedElement._prev
      removedElement._prev = nil
   else
      -- 最后一个节点是列表中唯一的节点
      self.first = nil
      self.last = nil
   end
  
   -- 减少长度
   self.length = self.length - 1
  
   return removedElement
end

-- 移除指定的元素 t
function list:remove(t)
   -- 如果要删除的节点有下一个节点
   -- 更新前一个和后一个节点的指针
   if t._next then
      if t._prev then
         t._next._prev = t._prev
         t._prev._next = t._next
      else
         -- 这是第一个节点
         t._next._prev = nil
         self._first = t._next
       end
   elseif t._prev then  -- 如果节点只有前一个节点
      -- 这是最后一个节点
      t._prev._next = nil
      self._last = t._prev
   else
      -- 这是唯一的节点
      self._first = nil
      self._last = nil
   end

   t._next = nil
   t._prev = nil
   self.length = self.length - 1
end

步骤 5:在 List 上测试移除操作

首先用几个值初始化一个列表,然后移除几个元素。

-- 创建一个带有值的新列表
local l = list({ "Mon" }, { "Tue" }, wed, { "Thu" }, { "Fri" })

print("原始列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

l:removeLast()
print("更新后的列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

l:remove (wed)
print("更新后的列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

完整示例 - 从列表中移除元素

以下是插入和遍历列表元素的完整示例。

main.lua

-- 列表实现
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 })

-- 将元素推入列表末尾
function list:push(t)
   -- 移动到最后一个节点    
   if self.last then
      self.last._next = t
      t._prev = self.last
      self.last = t
   else
      -- 将节点设置为第一个节点
      self.first = t
      self.last = t
   end
   -- 增加列表长度
   self.length = self.length + 1
end

-- 遍历列表
local function iterate(self, current)
   if not current then
      current = self.first
   elseif current then
      current = current._next
   end
  
   return current
end

function list:iterate()
   return iterate, self, nil
end

-- 从列表中移除最后一个元素
function list:removeLast()
   -- 如果最后一个节点为 nil 则返回
   if not self.last then
      return 
   end
   local removedElement = self.last
  
   -- 如果存在前一个节点
   -- 则将前一个节点设置为最后一个节点  
   if removedElement._prev then
      removedElement._prev._next = nil
      self.last = removedElement._prev
      removedElement._prev = nil
   else
      -- 最后一个节点是列表中唯一的节点
      self.first = nil
      self.last = nil
   end
  
   -- 减少长度
   self.length = self.length - 1
  
   return removedElement
end

-- 移除特定元素 t
function list:remove(t)
   -- 如果要删除的节点有下一个节点
   -- 更新前一个和下一个节点的指针
   if t._next then
      if t._prev then
         t._next._prev = t._prev
         t._prev._next = t._next
      else
         -- 这是第一个节点
         t._next._prev = nil
         self.first = t._next
      end
   elseif t._prev then  -- 如果节点只有前一个节点
      -- 这是最后一个节点
      t._prev._next = nil
      self.last = t._prev
   else
      -- 这是唯一的节点
      self.first = nil
      self.last = nil
   end

   t._next = nil
   t._prev = nil
   self.length = self.length - 1
end

local wed = { "Wed" }
-- 使用值创建新列表
local l = list({ "Mon" }, { "Tue" }, wed, { "Thu" }, { "Fri" })

print("原始列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

l:removeLast()
print("移除最后一个元素后的更新列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

l:remove(wed)
print("同时移除 Wed 后的更新列表")
-- 遍历条目
for v in l:iterate() do 
   print(v[1]) 
end

输出

运行上述代码时,将得到以下输出−

Original List
Mon
Tue
Wed
Thu
Fri
Updated List after removing last element
Mon
Tue
Wed
Thu
Updated List after removing Wed as well
Mon
Tue
Thu