使用Lua中的“pairs”函数以与编写顺序相同的顺序进行迭代。

有没有办法按照与下面相同的顺序循环遍历表格?

local tbl = {
    ["hello"] = 1,
    [2] = 2,
    [50] = 3,
    ["bye"] = 4,
    [200] = 5
}

我的意思是,当我使用“in pairs”时,每次执行代码都会得到不同的顺序...

我正在寻找类似于以下内容的内容:

function get_keys(tbl)
    local rtable = {}
    for k,v in pairs(tbl) do
        table.insert(rtable, k)
    end
    return rtable
end

local keys_of_tbl = get_keys(tbl)
for i = 1, table.getn(keys_of_tbl) do
    --Do something with: tbl[keys_of_tbl[i]]
end

但由于函数“get_keys”再次基于“在对中”,它不起作用...

点赞
用户258523
用户258523

不,表格没有“按照源代码编写”的顺序。(请注意,并非所有键都一定存在于源代码中。)对于非连续整数键,Lua 没有“按顺序”的概念。

如果您想要特定的顺序,则必须以某种方式手动保留该顺序。

如果您的表格中没有整数键,则可以使用它们作为您的顺序(并使用 ipairs 循环这些键,并将值作为键索引以获得真实值)。

如果您的原始值是您要排序的顺序,则可以循环并反向映射,以获取可以用 ipairs 迭代的表格。

2015-06-21 22:59:55
用户2726734
用户2726734

在 Lua 中,pairs 迭代键的顺序是未指定的。然而,您可以保存项目添加的顺序,使用基于数组的表,并且使用 ipairs(该迭代键在数组中具有定义的顺序)。为此,您可以使用元表创建自己的有序表,以便在添加新键时维护键顺序。


EDIT(先前的代码在更新时插入了多个键副本)

为此,您可以使用 __newindex,只要该索引尚未添加到表中,它就会被调用。ordered_add 方法会在隐藏表 _keys_values 中更新、删除或存储键。请注意,当我们更新键时,__newindex 也将始终被调用,因为我们没有将值存储在表中,而是将其存储在“隐藏”的表 _keys_values 中。

但请注意,我们不能在此表中使用任何键,键名 "_keys" 将覆盖我们的隐藏表,因此更安全的选择是使用 ordered_table.insert(t, key, value)ordered_table.index(t, key)ordered_table.remove(t, key) 方法。

ordered_table = {}

function ordered_table.insert(t, k, v)
  if not rawget(t._values, k) then -- 新键
    t._keys[#t._keys + 1] = k
  end
  if v == nil then -- 也删除键。
    ordered_table.remove(t, k)
  else -- 更新/存储值
    t._values[k] = v
  end
end

local function find(t, value)
  for i,v in ipairs(t) do
    if v == value then
      return i
    end
  end
end

function ordered_table.remove(t, k)
  local v = t._values[k]
  if v ~= nil then
    table.remove(t._keys, find(t._keys, k))
    t._values[k] = nil
  end
  return v
end

function ordered_table.index(t, k)
    return rawget(t._values, k)
end

function ordered_table.pairs(t)
  local i = 0
  return function()
    i = i + 1
    local key = t._keys[i]
    if key ~= nil then
      return key, t._values[key]
    end
  end
end

function ordered_table.new(init)
  init = init or {}
  local t = {_keys={}, _values={}}
  local n = #init
  if n % 2 ~= 0 then
    error"in ordered_table initialization: key is missing value"
  end
  for i=1,n/2 do
    local k = init[i * 2 - 1]
    local v = init[i * 2]
    if t._values[k] ~= nil then
      error("duplicate key:"..k)
    end
    t._keys[#t._keys + 1]  = k
    t._values[k] = v
  end
  return setmetatable(t,
    {__newindex=ordered_table.insert,
    __len=function(t) return #t._keys end,
    __pairs=ordered_table.pairs,
    __index=t._values
    })
end

--- 用法示例:
local t = ordered_table.new{
  "hello", 1,  -- 键值对
  2, 2,
  50, 3,
  "bye", 4,
  200, 5
}

print(#t)
print("hello is", t.hello)
print()
for k, v in pairs(t) do  --- Lua 5.2 __pairs metamethod
  print(k, v)
end
t.bye = nil -- 删除它
t[2] = 7 -- 使用整数键
print(#t)
2015-06-21 23:19:44