I have a lua table that I need to read sequentially, but the reading order is completely random
Table:
MP_STATS = {
ENABLE = true,
NOBLOCK = false,
RECOVERY = false,
EXPERIENCE = true,
....
}
Code example:
void read_test(void){
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, "test.lua") || lua_pcall(L, 0, 0, 0))
{
ShowError("Error reading 'test.lua'\n");
return;
}
lua_getglobal(L, "MP_STATS");
lua_pushnil(L);
while (lua_next(L, 1) != 0) {
const char *name = lua_tostring(L, 2);
if(check_exist_stats(name) == 0) {
printf("Stats %s not exist.\n", name);
lua_pop(L, 1);
continue;
}
lua_getfield(L, lua_gettop(L), name);
myvar = lua_toboolean(L, lua_gettop(L));
lua_pop(L, 1);
printf("%s\n", name);
}
lua_close(L);
printf("Read test.lua complete.\n");
}
When I run the program I have the following reading order
First run:
MP_NOBLOCK
MP_ENABLE
MP_EXPERIENCE
MP_RECOVERY
Second run:
MP_RECOVERY
MP_ENABLE
MP_NOBLOCK
MP_EXPERIENCE
Third run:
MP_ENABLE
MP_NOBLOCK
MP_EXPERIENCE
MP_RECOVERY
What should I do for reading to be done in sequence?
CodePudding user response:
Non-sequence entries of Lua tables use the hash part - that is, the order of traversal depends on the hashes of the keys; it does not depend on the order of key-value pairs in your table constructor (your code). Newer Lua versions will "randomize" hashes to mitigate hash collision attacks. This is why you get a different order each time.
The "fix" is to either:
- Keep your current table structure, but add a second table
local order = {"ENABLE", "NOBLOCK", "EXPERIENCE", "RECOVERY", ...}
to remember the order of the keys. Then loop over this second table, which uses the "array part" in order usingipairs
and use the values as keys for your current table structure. - Switch to a "list" for your
MP_STATS
table and use saidorder
table to look up keys for given indices. - Switch to a "list" of "pairs"
{key = "...", value = "..."}
which can be iterated in-order usingipairs
.
CodePudding user response:
Tables are associative arrays. Depending on the implementation, they may or may not provide a consistent ordering.
So does Lua use an implementation that returns a consistent ordering? As you already discovered, no. "The order in which the indices are enumerated is not specified, even for numeric indices", says the documentation for next
.
Lua does not provide the elements in the (unspecified) order you desire, because it returns the elements in an arbitrary order.
Note that the order isn't random, merely arbitrary.