如何有一个自动的for循环,替代嵌套的for循环?

How to have a auto for loops, alternative to nested for loops?

提问人:Hemant Bhargava 提问时间:7/13/2023 最后编辑:Jarod42Hemant Bhargava 更新时间:7/18/2023 访问量:216

问:

我想知道 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++ 算法 for-loop 自动 +-标准库 C +20

评论

1赞 Jerry Coffin 7/13/2023
简短的回答:不。更长的答案:标准库中的几乎所有内容都是围绕使用迭代器设计的,这不适合您使用循环(无论使用)。auto
0赞 Pepijn Kramer 7/13/2023
如果你真的专注于有一个循环:你可以先做一个允许访问索引对的函数,然后你可以遍历该对列表:onlinegdb.com/c_30co3rL。效率不高,所以我认为您的第一个解决方案(仅使用索引)或迭代器版本(不太可能越界)没有任何问题
1赞 HolyBlackCat 7/13/2023
你可以编写一个包装数组的帮助程序,它将以你期望的方式进行迭代(查看“范围适配器”)。for ( : )

答:

0赞 tjaehnig 7/13/2023 #1

您可以在循环中使用。像这样的东西: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

评论

1赞 HolyBlackCat 7/13/2023
您假设 OP 想要在匹配元素之后停止,但情况可能并非如此。
1赞 Pepijn Kramer 7/13/2023
it+1可能会越界,因此使用起来不安全。
0赞 tjaehnig 7/14/2023
@PepijnKramer it+1 最终会变成 vec.end(),然后是 first == last,所以 lambda 不会被调用
4赞 JeJo 7/13/2023 #2

我想知道 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 的现场演示

此外,这使您能够拥有并超越循环范围。ijconst


旁注:对于早于 C++20 的编译器,可以很容易地实现一个与 std::ranges::iota_view 完全相同的迭代器

0赞 Fabio A. 7/13/2023 #3

在 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赞 Saint-Martin 7/14/2023 #4

为什么不创建一个嵌入两个循环索引的 SuperIndex 类呢?

#include <iostream>
#include <vector>

class SuperIndex {
public :
  SuperIndex (int s = 0) : siz_ (s), i_ (0), j_ (0) {}
  ~SuperIndex () {}
  SuperIndex (const SuperIndex& si) : siz_ (si.siz_), i_ (si.i_), j_ (si.j_) {}
  SuperIndex& operator = (const SuperIndex& si) {
    siz_ = si.siz_; i_ = si.i_; j_ = si.j_;
    return *this;
  }
  bool operator == (const SuperIndex& si) const {
    return (siz_ == si.siz_) && (i_ == si.i_) && (j_ == si.j_);
  }
  bool operator != (const SuperIndex& si) const {return !operator == (si);}
  int i () const {return i_;}
  int j () const {return j_;}
  void operator ++ () {
    ++j_;
    if (j_ == siz_) {++i_; j_ = i_;}
  }
  bool is_sup () const {return (i_ >= siz_);}
  void write (std::ostream& os) const {
    os << siz_ << ":" << i_ << ", " << j_;
  }
private :
  int siz_;
  int i_;
  int j_;
};

用法,只有一个循环:

int main (int argc, char* argv []) {
  std::vector<int> vec {1, 2, 3, 4};
  auto si (SuperIndex (vec.size ()));
  for (;!si.is_sup (); ++si) {
    if (si.i () == si.j ()) continue;
    std::cout << "comparing " << vec [si.i ()] << " and " << vec [si.j ()] << std::endl;
  }
  return 0;
}

SuperIndex 类可以升级为 SuperIterator 类,基于相同的思路(成员 i_ 和 j_ 是 vector::iterator)......