有没有一种方法可以遍历两个容器(一个接着另一个),而无需使用两个for循环。
我打算做这样的事情
vector<int> a{ 1,2,3 };
vector<int> b{ 4,5,6 };
auto it = a.begin();
auto end = b.end();
for (; it != end; ++it)
{
if (it == a.end())
{
it = b.begin();
}
// do something with *it
}
要打印
1 2 3 4 5 6
(当然不起作用。解释在此answer中)
我不想编写两个for循环并在循环内复制代码。
是否可以通过单个for循环在a
之后b
上进行迭代?
我唯一想到的是将第二个容器复制/移动到第一个容器,或者创建一个结合了a
和b
的新向量,然后对其进行迭代。我也不想这样做,因为这将意味着昂贵的复制操作。
答案 0 :(得分:8)
使用range-v3处理C ++ 17或更早版本中与范围相关的所有事情:
for (int i : view::concat(a, b)) {
std::cout << i << ' ';
}
答案 1 :(得分:2)
Boost Range和标准库算法是解决方案,由于其更好的设计而应首选。
但是,仅出于完整性考虑,如果您确实想将设计思想应用到设计背后,则可以编写如下代码:
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};
for (auto it = v1.begin(); it != v2.end();) {
if (it == v1.end()) {
it = v2.begin();
} else {
// {
// use of *it
// }
++it;
}
}
答案 2 :(得分:2)
使用增强范围的另一种方法
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/join.hpp>
int main()
{
std::vector<int> a{ 1,2,3 };
std::vector<int> b{ 4,5,6 };
for(auto& x : boost::join(a, b)) {
std::cout << x << " ";
}
std::cout << std::endl;
}
答案 3 :(得分:1)
您可以像这样使用boost::range::join:
#include <boost/range/join.hpp>
...
std::vector<int> a{ 1,2,3 };
std::vector<int> b{ 4,5,6 };
for (auto i : boost::range::join(a, b))
{
...
}
答案 4 :(得分:1)
找到一种简单的“传统”方式来做到这一点。
for (int i = 0; i < 2; i++)
{
auto it = (i == 0) ? a.begin() : b.begin();
auto end = (i == 0) ? a.end() : b.end();
for (; it != end; ++it)
{
// do something with *it
}
}
答案 5 :(得分:1)
如果您想编写自己的书,则可以使用以下帮助:
template<class ForwardItr>
struct range {
ForwardItr beg;
ForwardItr end;
};
template<class ForwardItr, class F>
void concat_ranges(range<ForwardItr> r1, range<ForwardItr> r2, F f) {
auto run = [&f](range<ForwardItr> r) {
for(auto itr = r.beg; itr != r.end; ++itr){
f(*itr);
}
};
run(r1);
run(r2);
};
答案 6 :(得分:0)
好吧...您的错误是一个双重等于,您需要一个单一相等。
我的意思不是
YelpModel
但是
if (it == a.end())
{
it == b.begin();
} // ^^ Wrong!
但是我认为这不是一个好主意:我们确定if (it == a.end())
{
it = b.begin();
} // ^ correct
吗?
您的代码取决于此。
答案 7 :(得分:0)
打印这些容器甚至不需要一个for()
循环,如果您按如下方式使用std::copy
,
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main(int , char *[])
{
std::vector< int> a{ 1, 2, 3};
std::vector< int> b{ 4, 5, 6};
std::copy( a.begin(), a.end(), std::ostream_iterator< int>( std::cout, " "));
std::copy( b.begin(), b.end(), std::ostream_iterator< int>( std::cout, " "));
std::cout<< std::endl;
return 0;
}
输出:1 2 3 4 5 6
最好使用stl库,并且不需要编写任何代码即可打印容器。
根据您的关注我不想编写两个for循环并在循环内复制代码。有没有一种方法可以使用单个for循环迭代a之后的b?
避免重复代码的方法是可以在多个地方使用的写函数,例如,如果您不想使用std::copy
,并且想编写自己的代码来打印这些容器(不是推荐),然后您可以编写以下功能,
template< typename ForwardIterator>
void print( ForwardIterator begin, ForwardIterator end, const std::string& separator)
{
while( begin != end)
{
std::cout<< *begin<< separator;
++begin;
}
}
然后调用print
函数,
print( a.begin(), a.end(), std::string( " "));
print( b.begin(), b.end(), std::string( " "));
答案 8 :(得分:-1)
要获得最佳代码,最好避免在每个循环中进行不必要的测试。由于最有效的代码包含执行两个循环,因此可以通过更改参与循环的变量的整个状态(迭代器和哨兵)来接近该状态(我想这是实现串联范围的方法)。 ..这就是我的做法):
vector<int> a{ 1,2,3 };
vector<int> b{ 4,5,6 };
auto it = a.begin();
auto end = a.end();
for (;[&](){
if (it==end){
if (end==a.end()) {
it=b.begin();
end=b.end();
return true;
}
else return false;
}
return true;
}();
++it)
{
//loop content
}