我有一个复杂的Python多层字典,我想知道如何将这样的东西“翻译”为C++。我只是 C++ 的初学者,所以我使用 C++20 标准,我的 IDE 是 Visual Studio 2022,我想知道在 C++20 中是否有更简单的方法来做到这一点。
在这个例子中,第一级键是字符串,第一级值都是类似结构的字典。第二级键都是字符串,但值可以是整数、列表和字典。如果第三层是列表,则它是整数列表,否则如果最后一个结构是字典,则它是将整数映射到整数的字典。
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
}
}
}
这个例子显示了井字棋中第一个玩家可以从起始状态获胜的所有方式,我已经计算了如果玩家 O 首先移动,从起始开始可以到达的所有 5478 个状态,如果另一个玩家先移动,我也计算了相同的结果首先移动,总共 8533 个状态。
数据显示游戏是否结束、玩家 O 可以从状态中获胜的所有方式、状态可以导致平局状态的所有方式、所有合法的移动以及每个移动可以导致获胜的所有可能方式,或领带。
"high_stake"
表示玩家获胜的所有可能方式减去游戏以平局结束的所有可能方式,负值设置为 0。
几天前我用Python计算了它们,我没有使用C++,因为我不知道如何在C++中声明这个结构。
在 C++ 语法中,数据为:
{
{" ", {
{"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}
}}
}
}
}
这个怪物的类型标识符是什么?知道我在同一本词典中还有 5477 个其他此类结构。
我知道如何声明各个对象:
#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
}}};
我如何声明这些对象?我将用 C++ 计算结果,并将对象序列化到文件中。统计数据将计算一次,其他 C++ 程序将对结果进行反序列化。
如何保证类型不会改变?我知道我不能使用 JSON 或任何基于人类可读文本的序列化格式。我实际上使用 pickle 来存储数据,这就是我的 Python 程序实际加载的数据。为此,我应该使用 C++ 标准库 提供的哪种二进制序列化格式?
我知道 JSON 不能使用整数作为键,我需要整数键保持整数。另外,我已经对它进行了基准测试,JSON 序列化很慢。
考虑使用 Boost PropertyTree 库。它有一个 JSON 解析器,可将输入 JSON 文件转换为
boost::property_tree::ptree
对象。您可以轻松访问键和值。
这是一个示例 在 Coliru 上直播
#include <iostream>
#include <sstream>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
namespace pt = boost::property_tree;
int main() {
std::string json_str = R"(
{
"info": {
"over": false,
"wins": 131184,
"ties": 46080.5,
"legal_moves": [
0,
1
],
"win_moves": {
"0": 14652,
"1": 14232
}
}
}
)";
// Parse the JSON string
std::stringstream json_stream(json_str);
pt::ptree root;
pt::read_json({json_stream}, root);
// Access value of a leave node with
{
auto over = root.get_child("info").get_child("over").get_value<bool>();
std::cout << "over = " << over << std::endl;
}
// boolean
auto over = root.get_child("info.over").get_value<bool>();
std::cout << "over = " << over << std::endl;
// integer number
auto wins = root.get_child("info.wins").get_value<int>();
std::cout << "wins = " << wins << std::endl;
// floating-point number
auto ties = root.get_child("info.ties").get_value<double>();
std::cout << "ties = " << ties << std::endl;
// array of numbers
std::cout << "legal_moves:\n";
for (const auto &it : root.get_child("info.legal_moves")) {
std::cout << it.second.get_value<int>() << std::endl;
}
// nested object
std::cout << "win_moves:\n";
for (const auto &it : root.get_child("info.win_moves")) {
auto key = it.first;
auto val = it.second.get_value<int>();
std::cout << key << " : " << val << std::endl;
}
}
请注意,
boost.property_tree
保留了值的原始顺序,而另一个流行的包JsonCpp将根据底层的std::map<>
容器对值进行排序。
我还稍微修改了你原来的 JSON 字符串:
boost::property_tree::read_json
要求 JSON 键为 string
s。" "
作为键,调用get_child(" ").get_child("...")
来获取子节点。False
=> false
允许 get_value<bool>()
;否则,您必须将其解析为 string
,然后手动转换为 bool
。