Closed gsisinna closed 5 months ago
Sol tables are just lua tables. And lua tables are not guaranteed to be ordered, so the assumption in step 1 that the code creates the table with specific order is incorrect. As I understand, tables are basically hash maps.
The order of the assignments in a constructor is undefined.
The for_each documentation tells that it does not guarantee order.
The iterators you use to walk through a sol::table are NOT guaranteed to iterate in numeric order
Furthermore, in lua you can only A) iterate through a table by specifying the keys to iterate yourself and accessing that specific key in a loop, B) by iterating from 1 up to the first absent index (ipairs), C) by looping through all keys in the table with pairs which does not guarantee order (pairs calls next). for_each in sol is the same as pairs so it will never have guaranteed order even if the data would be ordered, and from the documentation of next
which pairs uses:
The order in which the indices are enumerated is not specified, even for numeric indices.
To collect all of this together, what you can do is create an ordered list containing the data instead and iterate through it using ipairs (or in sol, just get length and iterate from 1 to length):
// myTable = {
// { first = 1 },
// { second = 2 },
// { third = 3 },
// }
sol::table myTable = lua.create_table();
myTable[1] = lua.create_table_with(1, "first", 2, 1);
myTable[2] = lua.create_table_with(1, "second", 2, 2);
myTable[3] = lua.create_table_with(1, "third", 2, 3);
for (int i = 1, count = myTable.size(); i <= count; ++i) {
lua["print"](i, myTable[i], myTable[i][1], myTable[i][2]);
}
This is a lot less efficient and inconvenient overall but it guarantees order. There are of course other options, like creating your own data structure, or exposing some kind of C++ data structure to lua depending on what you need. On that vein, if you want an easy way for ordering while having a regular map, you could track the insertions and deletions from the table in a separate list. However, seems that for_each in sol does not check the metamethod __pairs
π€. We could expose the order table and iterate through it instead.
In general only lists, stacks, queues and similar data structures have insertion order preserved. Maps and sets order the data on its own, based on the keys or values usually, so they may not suit your needs if you require insertion order being preserved. I would say that JavaScript is quite unique in its implementation of a map style structure with insertion order when iterated (ref). Not sure I have seen anything similar elsewhere yet. π
@Rochet2 thank you very much for the technical explanation and support. I have continued to read the documentation of both Lua and Sol2 and will try to implement one of your proposed methods to achieve separate sorting. Basically, even if I do not respect the insertion order I need the keys to always be in a certain order before conversion to Json. In general, I am well aware of the pattern to be followed for the final result in terms of key sorting, but I am trying to get something that scales well for future software modifications and customization of results ππ»
First of all, thank you for this library and the effort that was put into it!
Description I'm using the sol2 library along with the nlohmann JSON library in my project. I need to preserve the ordering of data in sol tables and then convert them to ordered JSON using the nlohmann JSON library. However, it seems that the default behavior of sol2 doesn't preserve ordering when converting sol tables to JSON.
Expected Behavior: When converting sol tables to JSON, the ordering of elements should be preserved, ensuring that the JSON output maintains the same order as the original sol table.
Steps to Reproduce:
Create a sol table and populate it with data, ensuring that the data has a specific order:
Convert the sol table to JSON using sol2:
nlohmann::ordered_json tableToJson(sol::table table) { nlohmann::ordered_json json; table.for_each([&json](sol::object const& key, sol::object const& value) { if (key.is()) {
std::string keyStr = key.as();
if (value.is()) {
json[keyStr] = value.as();
} else if (value.is()) {
json[keyStr] = value.as();
} else if (value.is()) {
json[keyStr] = value.as();
} else if (value.is()) {
json[keyStr] = value.as();
} else if (value.is()) {
json[keyStr] = tableToJson(value.as());
} else {
// Handle other types if needed
}
}
});
return json;
}
Output:
Additional Information: I'm currently using the nlohmann ordered JSON library (nlohmann::ordered_json) to handle JSON objects. It would be helpful to have guidance on how to correctly store data in sol tables while preserving ordering and then convert them to ordered JSON using sol2.
Environment: Operating System: WSL2 (Debian) Compiler: Clang 14.0.6 x86_64 sol2 Version: 3.3.0 nlohmann JSON Version: 3.11.2
Full Code:
Thanks a lot for the support!