我想创建一个自定义迭代器,它将按此表中的颜色和数字值排序:
t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
for i, v in ipairs(t1) do
Note(i," ",v[1]," ",v[2])
end
现在这将输出:
1 green 1
2 red 3
3 green 2
4 yellow 5
5 red 4
我想要的输出是:
4 yellow 5
3 green 2
1 green 1
5 red 4
2 red 3
我可以使用自定义迭代器实现此目的吗?
编辑:我想要这样的东西,但我似乎无法解决这个问题:function sort_colours(t) -- sort table
local T = { }
for i, v in ipairs(t) do
T[#T + 1] = { i = i, v = v }
end
local order = {yellow = 1, green = 2, red = 3} -- desired order for colors
table.sort(T, function(a, b)
-- since you seem to want large-to-small when colors are the same,
-- use b[2] < a[2] comparison
if a[1] == b[1] then return b[2] < a[2] end
return order[a[1]] < order[b[1]]
end)
for i = 1, #T do
T[i] = T[i].i
end
local i = 0
return function() -- iterator function
i = i + 1
if T[i] then
return T[i], t[T[i]]
end
end
end
local t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
for k, v in sort_colours(t1) do print(k, v[1], v[2]) end
答案 0 :(得分:2)
你的尝试非常接近。您只需要记住,a
比较函数中的b
和table.sort
参数引用T
数组的元素,这些元素具有i
和{ {1}}字段(以及v
字段包含您实际要比较的值):
v
代码中的第二个function sort_colours(t)
local T = { }
for i, v in ipairs(t) do
T[#T+1] = { i = i, v = v } -- could just use T[i] here!
end
local order = {yellow = 1, green = 2, red = 3}
table.sort(T, function(a, b)
if a.v[1] == b.v[1] then return b.v[2] < a.v[2] end
return order[a.v[1]] < order[b.v[1]]
end)
local i = 0
return function()
i = i + 1
if T[i] then
return T[i].i, T[i].v
end
end
end
local t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
for k, v in sort_colours(t1) do print(k, v[1], v[2]) end
循环(for
)是不必要的,因为您基本上丢弃了刚排序的大部分数据。但我认为你试图做的是解决这类问题的常用方法:在原始数组中创建(和排序)索引数组,并且不要复制数据本身。这是一个例子(这次将一些有趣的东西作为更通用/可重用的函数):
for i = 1, #T do T[i] = T[i].i end
只要原始数组在迭代期间不发生变化,两种方法的工作方式都相同。如果确实如此(因为您添加/删除元素,或者因为涉及行为不当的-- default compare function
local function lessthan(a, b)
return a < b
end
function sorted_ipairs(t, f)
f = f or lessthan
local indices = {}
for i in ipairs(t) do
indices[i] = i
end
table.sort(indices, function(a, b)
return f(t[a], t[b])
end )
local i = 1
return function()
local index = indices[i]
if index then
i = i + 1
return index, t[index]
end
end
end
local order = {yellow = 1, green = 2, red = 3}
local function colour_compare(a, b)
if a[1] == b[1] then return b[2] < a[2] end
return order[a[1]] < order[b[1]]
end
for k, v in sorted_ipairs(t1, colour_compare) do print(k, v[1], v[2]) end
元方法),第一种方法更可预测,因为它适用于数据的快照。
对于样本数据,两种情况下的输出都相同:
__index
答案 1 :(得分:2)
在不知道代码的原因或如何实现代码的情况下,我已经创建了一个迭代器,它应该在大多数情况下都可以工作。除非你真的很奇怪地使用克隆,正如siffiejoe在评论中指出的那样。
我的方法是创建表的克隆并对其进行排序,然后返回迭代器,以便您可以在通用中调用它:
t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
function ByColor(t,order)
local order = order or {yellow=1,green=2,red=3}
local nt = {table.unpack(t)}
table.sort(nt, function(a,b)
order[a[1]] < order[b[1]] or order[a[1]] == order[b[1]] and a[2] > b[2]
end)
local helper = 1
return function(ti,v)
local nxt = nt[helper]
helper = helper + 1
for i,v in ipairs(t) do
if v == nxt then
return i,nxt
end
end
return nil
end
end
for i,v in ByColor(t1) do
print(i,v[1],v[2])
end
它返回表中的实际索引,并为订单提供可选参数,假设您要从黄色/绿色/红色切换。
答案 2 :(得分:0)
在使用标准ipairs
进行迭代之前,您可以保留具有所需顺序的表并使用表:
local t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
local order = {yellow = 1, green = 2, red = 3} -- desired order for colors
table.sort(t1, function(a, b)
-- since you seem to want large-to-small when colors are the same,
-- use b[2] < a[2] comparison
if a[1] == b[1] then return b[2] < a[2] end
return order[a[1]] < order[b[1]]
end)
for k, v in ipairs(t1) do print(k, v[1], v[2]) end -- show the result
我得到以下结果,这可能是你想要的:
1 yellow 5
2 green 2
3 green 1
4 red 4
5 red 3