遍历向量中的所有(无序)元素对

Loop over all (unordered) pairs of elements in a vector

我有一些数据的 std::vector(在我的例子中是点),我想遍历所有不同的元素对。对的顺序并不重要(因为我只对点的距离感兴趣)。使用经典的 for 循环,我想做的是:

std::vector<double> vec{-1., 3., 5., -8., 123., ...};

for (std::vector<double>::size_type first = 0; first < vec.size(); ++first) {
    for (std::vector<double>::size_type second = first+1; second < vec.size();
         ++second) {
        // Compute something using std::fabs(vec.at(first)-vec.at(second))
    }
}

我现在的问题是,是否可以使用基于范围的循环更优雅地实现这一目标。

我不会尝试将其强制转换为基于范围的循环(因为设计内部循环的开始会很棘手),但我会直接使用迭代器来阐明循环体并编写代码较少依赖于您使用的特定容器:

for (auto first = vec.begin(); first != vec.end(); ++first){
    for (auto second = first + 1; second != vec.end(); ++second){
        // Your vec.at(first) is now simply *first.    
    }
}

请注意,first + 1 始终有效,因为在评估 first + 1 时,first 永远不会是 vec.end()

C++ 标准还要求

std::vector::at 检查提供的索引是否在向量的范围内(如果不在范围内则抛出 std::out_of_range 异常),这对你来说是不必要的开销。

I provide this answer only because OP want a way of doing that with range based for loops. It isn't more elegant than ordinary loops.

如果您的向量没有重复数字,您可以使用反向迭代而不是从第二个循环中的特定点开始,这样您就可以在迭代中使用基于范围的 for。

对于基于范围的循环的反向迭代,您需要一个适配器 class。

template <typename It>
class reverse_adapter
{
public:
    reverse_adapter(It rbegin, It rend)
        : _rbegin(rbegin), _rend(rend)
    {}

    It begin() const { return _rbegin; }

    It end() const { return _rend; }

private:
    It _rbegin;
    It _rend;
};

template<typename Container>
reverse_adapter<typename Container::reverse_iterator> make_reverse(Container& container)
{
    reverse_adapter<typename Container::reverse_iterator> adapter(std::rbegin(container), std::rend(container));
    return adapter;
}

并在第二个循环中使用此适配器进行反向迭代。

for(auto val : vec)
{
    for (auto second_val : make_reverse(vec)) // Start from last to current item in first loop
    {
        if (val == second_val) break; // Instead of first + 1 in second loop

        auto dif = val - second_val;
    }
}