Lua: 自定义迭代器按颜色排序?

我想创建一个自定义迭代器,按颜色和数字值对这个表进行排序:

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
点赞
用户1442917
用户1442917

你可以在使用标准的 ipairs 迭代前,保持一个按需排序的表:

local t1 = {{"green", 1},{"red", 3},{"green", 2},{"yellow", 5},{"red", 4}}
local order = {yellow = 1, green = 2, red = 3} -- 颜色的期望顺序
table.sort(t1, function(a, b)
    -- 由于您似乎希望颜色相同时按从大到小排序,
    -- 应使用 b[2] < a[2] 比较
    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 -- 显示结果

我得到了以下结果,这可能是您想要的:

1   yellow  5
2   green   2
3   green   1
4   red 4
5   red 3
2016-01-25 07:25:15
用户3677376
用户3677376

你的尝试非常接近了。你只需要记住 table.sort 的比较函数中的 ab 参数是 T 数组的元素,它们有 iv 字段(v 字段包含你实际想要比较的值):

function sort_colours(t)
    local T = { }
    for i, v in ipairs(t) do
        T[#T+1] = { i = i, v = v } -- 这里也可以直接用 T[i]!
    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)是不必要的,因为你基本上扔掉了你刚刚排序的大部分数据。但是我认为你想做的是这种问题的常用方法:创建(和排序)原始数组的索引数组,而不是复制数据本身。以下是一个示例(这次做得更有趣一些,作为一个更一般/可重用的函数):

-- 默认比较函数
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 元方法),两种方法都可以正常工作。如果原始数组确实发生了更改,第一种方法更可预测,因为它是基于数据快照的。

对于示例数据,两种方法的输出是相同的:

4   yellow  5
3   green   2
1   green   1
5   red 4
2   red 3
2016-01-25 10:33:38
用户3979429
用户3979429

在不知道您的代码原因或如何实现它的情况下,我已经创建了一个迭代器,应该会大部分时间都有效。除非您正在像评论中指出的那样非常奇怪地使用克隆。

我的方法是围绕创建表的克隆并对其进行排序,然后返回一个迭代器,以便您可以在通用循环中调用它:

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)
      return 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

它返回您表格中的实际索引,并提供一个可选参数用于排序,假设您想从黄色/绿色/红色切换。

2016-01-25 12:05:33