【发布时间】:2011-06-22 01:50:38
【问题描述】:
我在 Lua 中有一个数组 x。我想设置head = x[1] 和rest = 数组的其余部分,以便rest[1] = x[2]、rest[2] = x[3] 等
我该怎么做?
(注意:我不在乎原始数组是否发生了变异。在 Javascript 中,我会执行 head = x.shift() 和 x 将包含剩余的元素。)
【问题讨论】:
我在 Lua 中有一个数组 x。我想设置head = x[1] 和rest = 数组的其余部分,以便rest[1] = x[2]、rest[2] = x[3] 等
我该怎么做?
(注意:我不在乎原始数组是否发生了变异。在 Javascript 中,我会执行 head = x.shift() 和 x 将包含剩余的元素。)
【问题讨论】:
“Pop”有点用词不当,因为它意味着一种廉价的操作,并且删除表格的第一个元素需要重新定位其余的内容——因此在 JavaScript 和其他一些语言中称为“shift”。
【讨论】:
你想要table.remove:
local t = {1,2,3,4}
local head = table.remove(t,1)
print( head )
--> 1
print( #t )
--> 3
print( t[1] )
--> 2
正如@daurnimator 所指出的,这需要Lua 运行时中数组的底层实现付出很多努力,移动所有的表格元素。如果你可以反过来表示你的数组,调用数组中的最后一项head,那么对table.remove()的调用将是一个廉价的流行:
local t = {4,3,2,1}
local head = table.remove(t)
print(head)
--> 1
print( #t )
--> 3
print( t[#t] )
--> 2
或者,您可以选择将您的元素序列表示为linked list。在这种情况下,从列表头部弹出一个项目也是一种廉价的操作(但将一个项目推到末尾不是,除非您跟踪列表中的“尾部”):
local setm,getm = setmetatable,getmetatable
local linkedlist=setm({__index={
tail = function(l) while l.rest do l=l.rest end return l end, -- N.B. O(n)!
push = function(l,v,t) t=l:tail() t.rest=setm({val=v},getm(l)) return t end,
cram = function(l,v) return setm({val=v,rest=l},getm(l)) end,
each = function(l,v)
return function() if l then v,l=l.val,l.rest return v end end
end
}},{ __call=function(lmeta,v,...)
local head,tail=setm({val=v},lmeta) tail=head
for i,v in ipairs{...} do tail=tail:push(v) end
return head
end })
local numbers = linkedlist(1,2,3,4)
for n in numbers:each() do print(n) end
--> 1
--> 2
--> 3
--> 4
local head,rest = numbers.val, numbers.rest
print(head)
--> 1
for n in rest:each() do print(n) end
--> 2
--> 3
--> 4
local unrest = rest:cram('99')
for n in unrest:each() do print(n) end
--> 99
--> 2
--> 3
--> 4
特别注意
local head,rest = numbers.val, numbers.rest
不修改任何数据结构,而只是在链中的特定链接上为您提供rest 句柄。
【讨论】:
通常在 Lua 中将元素 x 插入序列中的操作...
例如:S={a,b,c,d,e,f} 到 S={a,b,c,x,d,e,f}
...非常耗时,因为 d 必须移动到索引 5,e 移动到索引 6 等等。
是否存在其他形式 S 的序列,其中 S[a]=b, S[b]=c,S[c]=d,S[d]=e 和 S[e]=f?这样,您所要做的就是输入:
S[c]=x S[x]=d
boom,x 仅在两次操作中位于 c 之后和 d 之前。
【讨论】: