I have a complex multi-layered dictionary in Python, and I want to know how to "translate" such thing to C++. I am just a beginner in C++ so I use C++20 standard, my IDE is Visual Studio 2022 and I want to know if in C++20 there is a simpler way to do it.
In this example, the first level keys are strings, and the first level values are all dictionaries of similar structures. The second level keys are all strings, but the values can be integers, lists and dictionaries. If the third level is a list, it is a list of integers, else if the last structure is a dictionary, it is a dictionary mapping integers to integers.
Example in Python:
{
" ": {
"over": False,
"wins": 131184,
"ties": 46080,
"legal_moves": [
0,
1,
2,
3,
4,
5,
6,
7,
8
],
"win_moves": {
0: 14652,
1: 14232,
2: 14652,
3: 14232,
4: 15648,
5: 14232,
6: 14652,
7: 14232,
8: 14652
},
"tie_moves": {
0: 5184,
1: 5184,
2: 5184,
3: 5184,
4: 4608,
5: 5184,
6: 5184,
7: 5184,
8: 5184
},
"high_stakes": {
0: 9468,
1: 9048,
2: 9468,
3: 9048,
4: 11040,
5: 9048,
6: 9468,
7: 9048,
8: 9468
}
}
}
The example shows all ways the first player can win from the starting state in Tic-Tac-Toe, I have computed this for all 5478 states reachable from the starting start if player O moves first, I have also computed the same if the other moves first, for a total of 8533 states.
The data shows whether the game is over, all ways player O can win from the state, and all ways the state can lead to a tie state, all legal moves, and for each move all possible ways the move can lead to a win, or a tie. "high_stake" means all possible ways the player can win minus all possible ways the game ends in a tie, negative values are set to 0.
I computed them in Python several days ago, I didn't use C++ because I don't know how to declare this structure in C++.
In C++ syntax, the data would be:
{
{" ", {
{"over", 0},
{"wins", 131184},
{"ties", 46080},
{"legal_moves", {
0,
1,
2,
3,
4,
5,
6,
7,
8
}},
{"win_moves", {
{0, 14652},
{1, 14232},
{2, 14652},
{3, 14232},
{4, 15648},
{5, 14232},
{6, 14652},
{7, 14232},
{8, 14652}
}},
{"tie_moves", {
{0, 5184},
{1, 5184},
{2, 5184},
{3, 5184},
{4, 4608},
{5, 5184},
{6, 5184},
{7, 5184},
{8, 5184}
}},
{"high_stakes", {
{0, 9468},
{1, 9048},
{2, 9468},
{3, 9048},
{4, 11040},
{5, 9048},
{6, 9468},
{7, 9048},
{8, 9468}
}}
}
}
}
What would be the type identifier of this monstrosity? Know I have 5477 other such structures in the same dictionary.
I know how to declare the individual objects:
#include <unordered_map>
#include <string>
using std::unordered_map
using std::string
unordered_map<int, int> high_stakes = {
{0, 9468},
{1, 9048},
{2, 9468},
{3, 9048},
{4, 11040},
{5, 9048},
{6, 9468},
{7, 9048},
{8, 9468}
};
unordered_map<string, unordered_map<int, int>> d1 = {{"high_stakes", {
{0, 9468},
{1, 9048},
{2, 9468},
{3, 9048},
{4, 11040},
{5, 9048},
{6, 9468},
{7, 9048},
{8, 9468}
}}};
unordered_map<string, int[9]> d2 = {{"legal_moves", {
0,
1,
2,
3,
4,
5,
6,
7,
8
}}};
How can I declare these objects? I am going to compute the results in C++, and serialize the objects to a file. The statistics will be computed once, and other C++ programs will deserialize the results.
How can I guarantee the type won't be changed? I know I can't use JSON or any human-readable text based serialization format. I actually used pickle to store the data and that is what my Python program actually loads. What binary serialization format provided by the C++ standard library should I use for this purpose?
I know JSON cannot have integers as keys, I need the integer keys stay integers. Plus, I have benchmarked it, JSON serialization is slow.
Consider using Boost PropertyTree library. It has a JSON parser to convert an input JSON file to a
boost::property_tree::ptreeobject. You can add and access nodes easily.If you don't want to start from a JSON, you can manually add nodes to a
boost::property_tree::ptree. Since Python 3.7,dictpreserves the insertion order, which makesBoost Propertyan ideal counterpart in C++. I think the keys and values are defaulted tostrings upon retrieval, but you can easily cast type with the utility functionget_value<T>().Anyway, here is an example Live on Coliru based on your JSON-like input with a few modifications,
Note that
boost::property_tree::read_json()preserves the original order of values, while another popular package JsonCpp will sort the values due to the underlyingstd::map<>container.I modified your original JSON-like string a bit:
boost::property_tree::read_json()requires that JSON keys bestrings." "as a key, callget_child(" ").get_child("...")to get child nodes.False=>falseto allowget_value<bool>(); otherwise, you have to parse it as astringand then convert toboolmanually.