4
votes

Consider the following lua table:

foo = {
    bar1 = {a = 1, b = 2, c = "hello"},
    bar2 = {a = 5, b = 2, c = "bbq"},
    bar3 = {a = 76, b = 13, c = "pwnd"}
}

I am trying to iterate this table using the lua C API to retrieve the key names, bar1, bar2 and bar3. I used the lua_next(L, -2) function to iterate as suggested by many, but the problem is that it returns the elements in random order. The order changes on each run.

I use the following code:

for( lua_pushnil(L); lua_next(L, -2) != 0; lua_pop(L, 1) )
{
    printf("%s\n", lua_tostring(L, -2));
}

Most of the time, the output is unordered, such as bar2 bar1 bar3. When lucky, it's ordered. Is there an easy way to loop the table keys in an ordered fashion? What would be the equivalent code as I use, but ordered? Thanks!

Edit:

I know I am using a map rather than an array. But in lua script we have ipairs which would work just fine for this case. I'm looking at the C API equivalent. I've found this stackoverflow answer which gives a different answer, but it doesn't work for me, so I wonder if that answer is good or relevant.

3
That sounds like Lua is internally storing the keys-values as a hash-table. If you want to maintain order, perhaps a better solution would be to store the bar entries as a list, rather than a mapVite Falcon

3 Answers

3
votes

No. The order that Lua traverses tables is undefined.

If you know that the keys are of the form barXXX, then you can create these keys as strings dynamically in the order you wish and then get the corresponding value from the table.

2
votes

Put the names in a C array, and then order them in C.

As others are saying, the order of keys returned by the hash portion of a table is not guaranteed.

Alternatively, use an array-like structure so you can use the array part:

foo = {
  {name = 'bar1', a = 1,  b = 2,  c = "hello"},
  {name = 'bar2', a = 5,  b = 2,  c = "bbq"},
  {name = 'bar3', a = 76, b = 13, c = "pwnd"}
}

So you can use ipairs or the equivalent to for i=1,#foo to iterate over the items in order.

1
votes

Checking Lua's documentation, the main structure that Lua supports is a Hash Table. Given that it's always going to be a hash-table, you'd probably want to reimplement foo as an array. The bar1, bar2, etc can be part of the entry into the array like so:

foo = {}
foo[0] = {name='bar1', ...}
foo[1] = {name='bar2', ...}
    ...

or as @lhf suggested, just build the bar names inside a for-loop (if you know it's in sequence) and retrieve the values from foo table.