如何使用自动 for 循环来替代嵌套 for 循环?

问题描述 投票:0回答:4

我想知道 C++ 中是否有一些可用的东西可以帮助我们在使用

auto
时迭代两个嵌套循环。比如说,我想将一个数组元素与所有其他元素进行比较。这就是我们传统的做法:

std::vector<int> vec {1, 2, 3, 4};

for (int i = 0; i < vec.size(); ++i) 
{
    for (int j = i + 1; j < vec.size(); ++j) 
    {
        if (vec[i] == vec[j]) {}
        // Compares 1 with 2, 3 and 4
        // Compares 2 with 3 and 4
    }
}

目的是使用

auto
来实现这一目标。

std::vector<int> vec{1, 2, 3, 4};

for (<auto>& i : vec)
//   ^^^^^^^
{
    // What should I write here so that I compare only the forward elements?
}

我们可能可以使用这样的东西:

for (auto it = vec.begin(); it != vec.end(); ++it)
{
    for (auto jt = it + 1; jt != vec.end(); ++jt) 
    {
        // Do a comparison here.
    }
}

第三个快照再次编写更多代码。我希望对普通的第二个快照有更多的了解。

问题本身提到过。

c++ algorithm for-loop auto std
4个回答
5
投票

我想知道 C++ 中是否有一些可用的东西可以帮助我们在使用

auto
时迭代两个嵌套循环。

不完全是你想要的;但是,使用

std::ranges::iota_view
(自 起),您可以编写基于嵌套范围的
for
循环,如下所示:

#include <ranges> // std::ranges::iota_view

for (const auto i : std::views::iota(0u, std::size(vec)))
{
    for (const auto j : std::views::iota(i + 1u, std::size(vec)))
    {
        if (vec[i] == vec[j])
        {
            // .....
        }
    }
}

在 godbolt.org 中观看现场演示

此外,这使您能够在循环范围内拥有

i
j
const


旁注:对于早于 C++20 的编译器,可以轻松实现一个与

std::ranges::iota_view
完全相同的迭代器。


1
投票

在 c++20 中,也许是这样的?

#include <span>

/*...*/ 

std::size_t offset = 0;

for (auto &i: vec) 
{
    for (auto &j: std::span(vec).subspan(++offset)) 
    {
        if (i == j) {}
        // Compares 1 with 2, 3 and 4
        // Compares 2 with 3 and 4           
    }
}

offset
保证始终为
<= vec.size()
,因此
subspan()
明确定义的

如果您不想引入新变量,这也可以,但可能会产生更详细的汇编并且看起来很不寻常:

for (auto &i: vec) 
{
    for (auto &j: std::span(vec).subspan(&i - vec.data() + 1)) 
    {
        if (i == j) {}
        // Compares 1 with 2, 3 and 4
        // Compares 2 with 3 and 4           
    }
}

对于最短的组件,让外部循环在跨度上进行迭代是最好的,这样就不必在每次外部迭代时构造跨度。

std::span span(vec);
std::size_t offset = 0;

for (auto &i: span) 
{
    for (auto &j: span.subspan(++offset)) 
    {
        if (i == j) {}
        // Compares 1 with 2, 3 and 4
        // Compares 2 with 3 and 4           
    }
}

0
投票

您可以在循环中使用

std::any_of
。像这样的东西:

#include <algorithm>

...

std::vector<int> vec = {1, 2, 3, 4, 2};
for(auto it = vec.begin(); it != vec.end(); ++it) {
    cout << std::any_of(it + 1, vec.end(), [it](int x){ return x == *it;});
}

这会产生输出

01000


0
投票

声明一个由两个迭代器成员组成的 SuperIterator 类:

#include <vector>
#include <iostream>
class SuperIterator {
public :
  SuperIterator (std::vector<int>::iterator beg, const std::vector<int>::iterator end) : i_ (beg), j_ (beg), end_ (end) {}
  ~SuperIterator () {}
  SuperIterator (const SuperIterator& i) : i_ (i.i_), j_ (i.j_), end_ (i.end_) {}
  bool operator == (const SuperIterator& i) const {return (i_ == i.i_) && (j_ == i.j_);}
  bool operator != (const SuperIterator& i) const {return !operator == (i);}
  SuperIterator& operator = (const SuperIterator& i) {i_ = i.i_; j_ = i.j_; end_ = i.end_;return *this;}
  void operator ++ () {
    ++j_; 
    if (j_ == end_) {
      ++i_;
      j_ = i_;
    }
  }
//private :
  std::vector<int>::iterator i_, j_;
  std::vector<int>::iterator end_;
};

用途:

int main (int argc, char* []) {
  std::vector<int> vec {1, 2, 3, 4};
  SuperIterator superbeg (vec.begin (), vec.end ()), superend (vec.end (), vec.end ());
  for (auto i (superbeg); i != superend; ++i) {
    std::cout << *i.i_ << "." << *i.j_ << "    ";
  }
  std::cout << std::endl;
  return 0;
}

显示预期结果: 1.1 1.2 1.3 1.4 2.2 2.3 2.4 3.3 3.4 4.4

仅使用了一个自动迭代器。

© www.soinside.com 2019 - 2024. All rights reserved.