英文:
How to have a auto for loops, alternative to nested for loops?
问题
std::vector<int> vec{1, 2, 3, 4};
for (auto it = vec.begin(); it != vec.end(); ++it)
{
for (auto jt = it + 1; jt != vec.end(); ++jt)
{
// 在这里进行比较。
}
}
英文:
I am wondering if there is something available in C++ which helps us to iterate over the two nested loops while using auto
. Say like, I would want to compare an array element with all other elements forward. This is how we do it traditionally:
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
}
}
The intention is to use auto
in order to achieve this.
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?
}
We can probably use something like this:
for (auto it = vec.begin(); it != vec.end(); ++it)
{
for (auto jt = it + 1; jt != vec.end(); ++jt)
{
// Do a comparison here.
}
}
And the third snapshot again writes more code. I am looking to get more insights on the plain second snapshot.
Mentioned in the question itself.
答案1
得分: 4
I am wondering if there is something available in C++ which helps us to iterate over the two nested loops while using auto
.
Not exactly what you wished for; However, with std::ranges::iota_view
(Since [tag:C++20]), you could write nested range-based for
loops like follows:
#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])
{
// .....
}
}
}
See a live demo in godbolt.org
Additionally, this enables you to have i
and j
be const
over the loop scope.
Side note: For compilers older than C++20, one could easily implement an iterator that act exactly like std::ranges::iota_view
.
英文:
> I am wondering if there is something available in C++ which helps us to iterate over the two nested loops while using auto
.
Not exactly what you wished for; However, with std::ranges::iota_view
(Since [tag:C++20]), you could write nested range-based for
loops like follows:
#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])
{
// .....
}
}
}
See a live demo in godbolt.org
Additionally, this enables you to have i
and j
be const
over the loop scope.
Side note: For compilers older than C++20, one could easily implement an iterator that act exactly like std::ranges::iota_view
.
答案2
得分: 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
。
英文:
you can use std::any_of
in your loop. Something like this:
#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;});
}
this produces an output 01000
答案3
得分: 0
#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` is guaranteed to be always `<= vec.size()`, hence `subspan()` is [well defined][1].
If you don't want to introduce a new variable, this would also work, but might produce more verbose assembly and look quite unusual:
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
}
}
For the shortest assembly, having the outer loop iterate over a span already is the best, so that the span doesn't have to be constructed at each outer iteration.
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
}
}
[1]: https://en.cppreference.com/w/cpp/container/span/subspan
英文:
In c++20, something like this, perhaps?
#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
is guaranteed to be always <= vec.size()
, hence subspan()
is well defined.
If you don't want to introduce a new variable, this would also work, but might produce more verbose assembly and look quite unusual:
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
}
}
For the shortest assembly, having the outer loop iterate over a span already is the best, so that the span doesn't have to be constructed at each outer iteration.
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
}
}
答案4
得分: 0
为什么不创建一个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)...
英文:
Why not create a SuperIndex class embedding the two loop index ?
#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_;
};
usage, only one loop :
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 class may be upgraded to a SuperIterator class, based on the same idea (members i_ and j_ are vector::iterator)...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论