Is there any way to loop trough a table like the one below in the same order as it's written?
local tbl = {
["hello"] = 1,
[2] = 2,
[50] = 3,
["bye"] = 4,
[200] = 5
}
What I mean is that when I use "in pairs" I'll get a different order everytime I execute my code ...
I'm searching for something like this:
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
But because the function "get_keys" is based on "in pairs" again, it won't work ...
In Lua, the order that pairs iterates through the keys is unspecified. However you can save the order in which items are added in an array-style table and use ipairs
(which has a defined order for iterating keys in an array). To help with that you can create your own ordered table using metatables so that the key order will be maintained when new keys are added.
EDIT (earlier code inserted multiple copies of the key on updates)
To do this you can use __newindex
which we be called so long as the index is not added yet to the table. The ordered_add
method updates, deletes, or stores the key in the hidden tables _keys
and _values
. Note that __newindex
will always be called when we update the key too since we didn't store the value in the table but instead stored it in the "hidden" tables _keys
and _values
.
Note however that we cannot use any key in this table, the key name "_keys"
will overwrite our hidden table so the safer alternative is to use the ordered_table.insert(t, key, value)
ordered_table.index(t, key)
and ordered_table.remove(t, key)
methods.
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)
No. There's no "as written in the source" order to tables. (Consider that not all keys necessarily exist in the source.) lua has no concept of "in order" for non-contiguous integer keys.
If you want a specific order you get to keep that order yourself manually in some way.
If you don't have any integer keys in your table then you can use those as your order (and use ipairs
to loop those keys and index the value as the key to get the real value).
If your original values are the order you want to sort in then you can loop and reverse map to get a table that you can iterate with ipairs
once done.
A friend of mine made me this little function which works fine too:
function switch_key_val(tbl)
local rtbl = {}
for k,v in pairs(tbl) do
rtbl[v] = k
end
return rtbl
end
This can be used like this:
local tbl = {
["hello"] = 1,
[2] = 2,
[50] = 3,
["bye"] = 4,
[200] = 5
}
local tbl = switch_key_val(tbl)
for v,k in pairs(tbl) do
print(k,v)
end
which gives me the same result everytime I execute my code
来源:https://stackoverflow.com/questions/30970034/lua-in-pairs-with-same-order-as-its-written