【问题标题】:Generalising multiple nested for loops泛化多个嵌套的 for 循环
【发布时间】:2018-02-21 12:09:39
【问题描述】:

我有这样的数据结构: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 对象。

那么,问题是,有没有什么方法可以在不损失性能的情况下对其进行概括?我想出了一个返回元组向量的函数:

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)

【问题讨论】:

  • 可以像Python的生成器一样定义迭代器。
  • 模板内联递归函数。
  • 也许尝试将reference_wrappers 存储在元组中?这将避免复制,但仍然允许您获取元组内的数据

标签: c++ for-loop nested generalization


【解决方案1】:

您的地图地图从一开始就没有效率。最好是整合关键部分:

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);

而且你避免了很多间接。如果您可以使用固定长度的字符串和/或将字符串组合到单个分配中,则更是如此。或者如果共享第一个和第二个键字符串很重要,您可以使用引用计数字符串类型。

【讨论】:

  • “您的地图地图从一开始就没有效率。”。取决于 OP 是否与中间地图一起使用。
【解决方案2】:

只需创建模板函数:

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 映射的模板。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 2012-02-15
    • 2021-01-15
    • 2012-01-27
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多