【问题标题】:Nested range-based for-loops嵌套的基于范围的 for 循环
【发布时间】:2013-07-22 12:19:51
【问题描述】:

我有以下代码使用基于范围的for-loops (C++11):

vector<atom> protein;
...
for(atom &atom1 : protein) {
    ...
    for(atom &atom2 : protein) {
        if(&atom1 != &atom2) {
                ...
        }
    }
}

有没有更好/更干净/更快的方法来编写这个嵌套循环?没有办法在第二个循环中包含if 条件吗?

【问题讨论】:

  • “更快”?更快的是,一旦你写了这个,不要浪费你的时间来重写它。 不是 不好。
  • 代替删除的对角线,您可以为严格的上三角形编写传统的for 循环,并将两个交换语句放入主体中。
  • 你可以写一个 for 循环而不是 foreach 循环,然后执行 'for(j = i +1...' 并保存 if 条件

标签: c++ for-loop c++11 nested-loops


【解决方案1】:

与 ronag 的回答类似的是一个更通用的版本:

template<typename C, typename Op>
void each_unique_pair(C& container, Op fun)
{
    for(auto it = container.begin(); it != container.end() - 1; ++it)
    {
        for(auto it2 = std::next(it); it2 != container.end(); ++it2)
        {
            fun(*it, *it2);
            fun(*it2, *it);
        }
    }
}

更新

template<typename C, typename O1, typename O2>
void each_value_and_pair(C& container, O1 val_fun, O2 pair_fun)
{
    auto it = std::begin(container);
    auto end = std::end(container);
    if(it == end)
        return;

    for(; it != std::prev(end); ++it)
    {
        val_fun(*it);
        for(auto it2 = std::next(it); it2 != end; ++it2)
        {
            pair_fun(*it2, *it);
            pair_fun(*it, *it2);
        }
    }
}

这样使用:

main()
{
    std::vector<char> values;
    // populate values
    // ....
    each_value_and_pair(values, 
        [](char c1) { std::cout << "value: " << c1 << std::endl;}, 
        [](char c1, char c2){std::cout << "pair: " << c1 << "-" << c2 << std::endl;});
}

【讨论】:

  • 那不一样。我只不要对角线,不只要上三角!
  • 为了最大的通用性,它应该是std::prev(std::end(container))而不是container.end()-1;并且您还需要正确处理空容器。
  • @PeterR :不,它仍然不一样,正如我对 MikeSeymour 所说的那样,在 for 循环之间 之间有特定于 atom1 的代码。
  • @Kyle_the_hacker 啊,当我第一次阅读您的帖子时,我错过了这种细微差别。我不确定通用版本对这种情况有用。我在原始代码下面发布了一个,只是为了好玩。
【解决方案2】:

悲伤但真实。 带有迭代器和 auto 关键字的普通循环怎么样?

【讨论】:

  • for (auto a = std::begin(arr); a != std::end(arr); ++a) \\ 下一行 for (auto b = a + 1; b != std::end(arr); ++b)
  • 那不一样。第二个循环中的 if 条件。
  • 既然您编辑了它(为什么不将它包含在答案中而不是评论中?),它的迭代次数只有原始代码的一半左右,所以它没有与原始行为相同。
  • 是的,它只有大约一半的迭代次数。但大多数情况下是正常的。
  • @herolover 但那不是做同样的事情。
【解决方案3】:

我认为这可能是您正在寻找的:

for(auto it1 = std::begin(protein1); it1 != std::end(protein); ++it1)
{
    for(auto it2 = std::next(it1); it2 != std::end(protein); ++it2)
    {
          auto& atom1 = *it1;
          auto& atom2 = *it2;

           // ...
    }
}

【讨论】:

  • 更像it2 = std::next(it1)
  • 那不一样。它只有大约一半的迭代次数。
  • 但我只不想要对角线,不只想要上三角。
  • @R.MartinhoFernandes:确实;这个(以及其他类似的答案)缺少的是你需要循环体为do_stuff_with(atom1,atom2); do_stuff_with(atom2,atom1); 才能获得原始行为。
  • @MikeSeymour 实际上我不能 do_stuff_with(atom1,atom2); do_stuff_with(atom2,atom1); 因为我有特定于 atom1 for 循环之间的代码。
【解决方案4】:

你的方法很好。 如果你想保存 if 语句,你可以

vector<atom> protein;
int i, j;
...
for(i = 0; i < protein.size() : i++) {
    atom &atom1 = protein.at(i);
    for(j = i+1; j < protein.size() ; j++) {
        atom &atom2 = protein.at(j);
                    // Do something
                    // Swap the atom2 and atom1
                    // Do something again
    }
}

【讨论】:

  • 那不一样。它只有大约一半的迭代次数。
  • 但我只不想要对角线,不只想要上三角。
  • @LiranElisha 现在它只循环通过下三角形:S
  • @R.MartinhoFernandes 你是对的。这是我做快速编辑的错。只需做两次你想做的事,除非是按特定顺序更改项目,然后我就没有主意了
猜你喜欢
  • 1970-01-01
  • 2016-10-31
  • 1970-01-01
  • 2014-12-06
  • 2014-01-12
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
相关资源
最近更新 更多