提问人:Hemant Bhargava 提问时间:7/13/2023 最后编辑:Jarod42Hemant Bhargava 更新时间:7/18/2023 访问量:216
如何有一个自动的for循环,替代嵌套的for循环?
How to have a auto for loops, alternative to nested for loops?
问:
我想知道 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.
}
}
第三个快照再次写入更多代码。我希望获得有关普通第二快照的更多见解。
在问题本身中提到。
答:
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(从 c++20 开始),您可以编写基于范围的嵌套循环,如下所示: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])
{
// .....
}
}
}
此外,这使您能够拥有并超越循环范围。i
j
const
旁注:对于早于 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)......
评论
auto
for ( : )