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

时间:2016-01-25 06:28:03

标签: sorting lua iterator

我想创建一个自定义迭代器,它将按此表中的颜色和数字值排序:

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

3 个答案:

答案 0 :(得分:2)

你的尝试非常接近。您只需要记住,a比较函数中的btable.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