Lua 成对,顺序与书写顺序相同
Lua in pairs with same order as it's written
有没有什么方法可以像下面这样按照写的顺序循环遍历 table?
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"又是基于"in pairs",所以不行...
没有。没有 "as written in the source" 到 table 的命令。 (考虑到并非所有键都一定存在于源代码中。)lua 对于非连续整数键没有 "in order" 的概念。
如果您想要一个特定的订单,您可以通过某种方式手动保留该订单。
如果您的 table 中没有任何整数键,那么您可以使用它们作为您的订单(并使用 ipairs
循环这些键并将值索引为键以获取实际价值)。
如果您的原始值是您想要排序的顺序,那么您可以循环和反向映射以获得一个 table,完成后您可以用 ipairs
进行迭代。
在 Lua 中,配对遍历键的顺序未指定。但是,您可以保存在数组样式 table 中添加项目的顺序并使用 ipairs
(它具有用于迭代数组中的键的定义顺序)。为此,您可以使用 metatables 创建自己的有序 table,以便在添加新键时保持键顺序。
EDIT(早期代码在更新时插入了密钥的多个副本)
为此,您可以使用 __newindex
,只要索引尚未添加到 table,我们就可以调用它。 ordered_add
方法更新、删除或存储隐藏 table 中的密钥 _keys
和 _values
。请注意,当我们也更新密钥时,将始终调用 __newindex
,因为我们没有将值存储在 table 中,而是将其存储在 "hidden" tables _keys
和 _values
.
但是请注意,我们不能在此 table 中使用任何密钥,密钥名称 "_keys"
将覆盖我们隐藏的 table 因此更安全的替代方法是使用 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 -- new key
t._keys[#t._keys + 1] = k
end
if v == nil then -- delete key too.
ordered_table.remove(t, k)
else -- update/store value
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
--- Example Usage:
local t = ordered_table.new{
"hello", 1, -- key, value pairs
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 -- delete that
t[2] = 7 -- use integer keys
print(#t)
有没有什么方法可以像下面这样按照写的顺序循环遍历 table?
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"又是基于"in pairs",所以不行...
没有。没有 "as written in the source" 到 table 的命令。 (考虑到并非所有键都一定存在于源代码中。)lua 对于非连续整数键没有 "in order" 的概念。
如果您想要一个特定的订单,您可以通过某种方式手动保留该订单。
如果您的 table 中没有任何整数键,那么您可以使用它们作为您的订单(并使用 ipairs
循环这些键并将值索引为键以获取实际价值)。
如果您的原始值是您想要排序的顺序,那么您可以循环和反向映射以获得一个 table,完成后您可以用 ipairs
进行迭代。
在 Lua 中,配对遍历键的顺序未指定。但是,您可以保存在数组样式 table 中添加项目的顺序并使用 ipairs
(它具有用于迭代数组中的键的定义顺序)。为此,您可以使用 metatables 创建自己的有序 table,以便在添加新键时保持键顺序。
EDIT(早期代码在更新时插入了密钥的多个副本)
为此,您可以使用 __newindex
,只要索引尚未添加到 table,我们就可以调用它。 ordered_add
方法更新、删除或存储隐藏 table 中的密钥 _keys
和 _values
。请注意,当我们也更新密钥时,将始终调用 __newindex
,因为我们没有将值存储在 table 中,而是将其存储在 "hidden" tables _keys
和 _values
.
但是请注意,我们不能在此 table 中使用任何密钥,密钥名称 "_keys"
将覆盖我们隐藏的 table 因此更安全的替代方法是使用 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 -- new key
t._keys[#t._keys + 1] = k
end
if v == nil then -- delete key too.
ordered_table.remove(t, k)
else -- update/store value
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
--- Example Usage:
local t = ordered_table.new{
"hello", 1, -- key, value pairs
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 -- delete that
t[2] = 7 -- use integer keys
print(#t)