在 Lua 的内置库中,table 提供了 table.remove(t,[num]) 来删除列表中的元素,因为在该函数的执行过程涉及到了内存的移动,所以在删除多个元素的时候,如果每次都调用该函数,就会造成多次内存移动。

针对这一点,对 table 进行一些删除操作上的性能优化,代码基本上是从 C# 源码中抄过来的:-D,介绍在这里,下面直接附上代码,里面注释比较清楚,有什么问题,希望能够留言指出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
local TableUtil = {}

---从列表 t 中删除从 pos 开始的 num 个元素。
---@t 删除元素的列表
---@pos 开始删除索引
---@num 要删除元素的数量,如果没有指定,则删除 pos 之后的所有元素
function TableUtil.ClearArray(t,pos,num)
assert(t ~= nil,"The array:t is nil")
assert(pos > 0 and pos<=#t,"The pos is out range")

--如果没有指定 num 值,则默认 pos 之后全部删除
num = num or #t

--需要删除的最后一个元素的索引
local index = 0
if num >= 0 then
index = pos + num - 1
else
--为了保持从尾往头删,调换头尾索引
pos,index = pos + num + 1,pos
end

--对头尾索引进行限制,避免超界
index = index > #t and #t or index
index = index < 1 and 1 or index
pos = pos < 1 and 1 or pos

local maxn = #t - index + pos - 1

table.move(t,index+1,#t,pos)

local temp = #t
while temp > maxn do
table.remove(t,temp)
temp = temp - 1
end
end

---从列表 t 中删除,所有满足 match 条件的元素
---@t 列表
---@match 筛选列表
function TableUtil.RemoveAll(t,match)
assert(match ~= nil,"Then match argument cannot be nil")

--找到第一个需要删除的元素的索引 num
local num = 1
while(num < #t and not match(t[num])) do
num = num + 1
end

--如果需要删除的索引超过列表最大索引,则表明没有满足删除条件的元素
if num > #t then
return 0
end

--将 num 之后不需要删除的元素,移动到需要删除的元素之前,这样可以避免拷贝
local i = num + 1
while(i <= #t) do

while(i <= #t and match(t[i])) do
i = i + 1
end

if i <= #t then
t[num] = t[i]
num = num + 1
i = i + 1
end
end
local result = #t - num + 1

--清楚需要删除的元素
ClearArray(t,num,result)
return result
end

return TableUtil