泛化多个嵌套的 for 循环
Generalising multiple nested for loops
我有这样的数据结构:map<string, map<string, map<string, MyObj>>>
现在,我有多个函数,它们都使用相同的 for 循环方法:
for (auto p1 : myMap)
for (auto p2 : p1.second)
for (auto p3 : p2.second)
doThingsWith(p1, p2, 3);
其中 doThingsWith(p1, p2, p3)
因函数以及 for 循环前后的代码而异。此外,例如,某些函数只需要访问 MyObj
对象,而其他函数则需要访问所有字符串键以及 MyObj
对象。
所以,问题是,有没有什么方法可以在不损失性能的情况下对此进行概括?我想出了一个 returns 元组向量的函数:
vector<tuple<string, string, string, MyObj>> getData(... &myMap)
{
vector<tuple<string, string, string, MyObj>> data;
for (auto p1 : myMap)
for (auto p2 : p1.second)
for (auto p3 : p2.second)
data.push_back(tuple<string, string, string, MyObj>(
p1.first, p2.first, p3.first, p3.second
));
return data;
}
现在我的函数可以使用这个:
for (auto t : getData(myMap))
doThingsWith(get<0>(t), get<1>(t), get<2>(t), get<3>(t));
但这不必要地构造了很多元组和向量,因为myMap
很大。
有没有更好的办法?在 Python 中,我可以使用生成器,但我不知道 C++ 等价物:
def iterTuples(myMap):
for k1, v1 in myMap.items():
for k2, v2 in v1.items():
for k3, v3 in v2.items():
yield k1, k2, k3, v3
for k1, k2, k3, val in iterTuples(myMap):
doThingsWith(k1, k2, k3, val)
简单创建模板函数:
template <typename Map3, typename F>
void ForEachAll(Map3&& m, F&& f)
{
for (auto&& p1 : m)
for (auto&& p2 : p1.second)
for (auto&& p3 : p2.second)
f(p1.first, p2.first, p3.first, p3.second);
}
template <typename Map3, typename F>
void ForEach(Map3&& m, F&& f)
{
for (auto&& p1 : m)
for (auto&& p2 : p1.second)
for (auto&& p3 : p2.second)
f(p3.second);
}
注:
- 你可以用一些SFINAE来命名它们
MAP3
是允许 const 而没有 const 映射的模板。
您的 map-of-maps-of-maps 从一开始就效率不高。更好的方法是合并关键部分:
typedef tuple<string, string, string> Key;
std::map<Key, MyObj> myMap;
现在您有了一个直接有效的解决方案:
for (const auto& pr : myMap)
doThingsWith(get<0>(pr.first), get<1>(pr.first), get<2>(pr.first), pr.second);
而且你避免了很多间接性。如果您可以使用 fixed-length 字符串 and/or 则更多,将字符串组合成一个分配。或者,如果共享第一个和第二个键字符串很重要,您可以使用 reference-counted 字符串类型。
我有这样的数据结构:map<string, map<string, map<string, MyObj>>>
现在,我有多个函数,它们都使用相同的 for 循环方法:
for (auto p1 : myMap)
for (auto p2 : p1.second)
for (auto p3 : p2.second)
doThingsWith(p1, p2, 3);
其中 doThingsWith(p1, p2, p3)
因函数以及 for 循环前后的代码而异。此外,例如,某些函数只需要访问 MyObj
对象,而其他函数则需要访问所有字符串键以及 MyObj
对象。
所以,问题是,有没有什么方法可以在不损失性能的情况下对此进行概括?我想出了一个 returns 元组向量的函数:
vector<tuple<string, string, string, MyObj>> getData(... &myMap)
{
vector<tuple<string, string, string, MyObj>> data;
for (auto p1 : myMap)
for (auto p2 : p1.second)
for (auto p3 : p2.second)
data.push_back(tuple<string, string, string, MyObj>(
p1.first, p2.first, p3.first, p3.second
));
return data;
}
现在我的函数可以使用这个:
for (auto t : getData(myMap))
doThingsWith(get<0>(t), get<1>(t), get<2>(t), get<3>(t));
但这不必要地构造了很多元组和向量,因为myMap
很大。
有没有更好的办法?在 Python 中,我可以使用生成器,但我不知道 C++ 等价物:
def iterTuples(myMap):
for k1, v1 in myMap.items():
for k2, v2 in v1.items():
for k3, v3 in v2.items():
yield k1, k2, k3, v3
for k1, k2, k3, val in iterTuples(myMap):
doThingsWith(k1, k2, k3, val)
简单创建模板函数:
template <typename Map3, typename F>
void ForEachAll(Map3&& m, F&& f)
{
for (auto&& p1 : m)
for (auto&& p2 : p1.second)
for (auto&& p3 : p2.second)
f(p1.first, p2.first, p3.first, p3.second);
}
template <typename Map3, typename F>
void ForEach(Map3&& m, F&& f)
{
for (auto&& p1 : m)
for (auto&& p2 : p1.second)
for (auto&& p3 : p2.second)
f(p3.second);
}
注:
- 你可以用一些SFINAE来命名它们
MAP3
是允许 const 而没有 const 映射的模板。
您的 map-of-maps-of-maps 从一开始就效率不高。更好的方法是合并关键部分:
typedef tuple<string, string, string> Key;
std::map<Key, MyObj> myMap;
现在您有了一个直接有效的解决方案:
for (const auto& pr : myMap)
doThingsWith(get<0>(pr.first), get<1>(pr.first), get<2>(pr.first), pr.second);
而且你避免了很多间接性。如果您可以使用 fixed-length 字符串 and/or 则更多,将字符串组合成一个分配。或者,如果共享第一个和第二个键字符串很重要,您可以使用 reference-counted 字符串类型。