C++ 如何使用 BOOST_FOREACH 同时迭代两个向量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7286755/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I iterate over two vectors simultaneously using BOOST_FOREACH?
提问by Candy Chiu
I'd like to replicate the following with BOOST FOREACH
我想用 BOOST FOREACH 复制以下内容
std::vector<int>::const_iterator i1;
std::vector<int>::const_iterator i2;
for( i1 = v1.begin(), i2 = v2.begin();
i1 < v1.end() && i2 < v2.end();
++i1, ++i2 )
{
doSomething( *i1, *i2 );
}
回答by Steve Jessop
Iterating over two things simultaneously is called a "zip" (from functional programming), and Boost has a zip iterator:
同时迭代两件事称为“zip”(来自函数式编程),Boost 有一个 zip 迭代器:
The zip iterator provides the ability to parallel-iterate over several controlled sequences simultaneously. A zip iterator is constructed from a tuple of iterators. Moving the zip iterator moves all the iterators in parallel. Dereferencing the zip iterator returns a tuple that contains the results of dereferencing the individual iterators.
zip 迭代器提供了同时对多个受控序列进行并行迭代的能力。zip 迭代器由迭代器元组构造而成。移动 zip 迭代器会并行移动所有迭代器。取消引用 zip 迭代器会返回一个元组,其中包含取消引用各个迭代器的结果。
Note that it's an iterator, not a range, so to use BOOST_FOREACH
you're going to have to stuff two of them into an iterator_rangeor pair
. So it won't be pretty, but with a bit of care you can probably come up with a simple zip_range
and write:
请注意,它是一个迭代器,而不是一个范围,因此要使用,BOOST_FOREACH
您必须将其中的两个填充到iterator_range或pair
. 所以它不会很漂亮,但稍加注意,你可能会想出一个简单的zip_range
写法:
BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
Or special-case for 2 and use std::pair
rather than boost::tuple
.
或 2 的特殊情况并使用std::pair
而不是boost::tuple
.
I suppose that since doSomething
might have parameters (int&, int&)
, actually we want a tuple<int&,int&>
. Hope it works.
我想因为doSomething
可能有参数(int&, int&)
,实际上我们想要一个tuple<int&,int&>
. 希望它有效。
回答by panda-34
If you use boost, I think it should be as simple as:
如果你使用boost,我认为应该很简单:
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
std::vector<int> v1;
std::vector<int> v2;
// iterate over values
int i1, i2;
BOOST_FOREACH(boost::tie(i1, i2), boost::combine(v1, v2))
std::cout << i1+i2 << "\n"; // sums two vectors
// iterate over references
typedef boost::tuple<int&, int&> int_ref_tuple;
BOOST_FOREACH(int_ref_tuple tup, boost::combine(v1, v2))
tup.get<0>() = tup.get<1>(); // assigns one vector to another
the strange part is that boost::combine is not documented. Works for me, anyway.
奇怪的部分是 boost::combine 没有记录。无论如何,对我有用。
回答by Nawaz
If you want to use BOOST_FOREACH
to iterate two vectors simultenously, as you've done in your sample code, then you've to encapsulate both vectors in a wrapper class which should expose begin
and end
functions. These functions return custom iterator to be used to iterate over the wrapper which internally will iterate over the two vectors. Doesn't sound good, but that is what you've to do.
如果您想同时BOOST_FOREACH
迭代两个向量,就像您在示例代码中所做的那样,那么您必须将这两个向量封装在一个应该公开begin
和end
函数的包装类中。这些函数返回自定义迭代器,用于在内部迭代两个向量的包装器上进行迭代。听起来不太好,但这是你必须做的。
This is my first attempt to implement this (minimal implementation just to demonstrate the basic idea):
这是我第一次尝试实现这个(最小实现只是为了演示基本思想):
template<typename T>
struct wrapper
{
struct iterator
{
typedef typename std::vector<T>::iterator It;
It it1, it2;
iterator(It it1, It it2) : it1(it1), it2(it2) {}
iterator & operator++()
{
++it1; ++it2; return *this;
}
iterator & operator *()
{
return *this;
}
bool operator == (const iterator &other)
{
return !(*this != other);
}
bool operator != (const iterator &other)
{
return it1 != other.it1 && it2 != other.it2;
}
};
iterator begin_, end_;
wrapper(std::vector<T> &v1, std::vector<T> &v2)
: begin_(v1.begin(), v2.begin()),end_(v1.end(), v2.end())
{
}
wrapper(const wrapper & other) : begin_(other.begin_), end_(other.end_) {}
iterator begin()
{
return begin_;
}
iterator end()
{
return end_;
}
};
And the following is the test code. Since it's using usual for
loop, because ideone has not installed for boost for C++0x or I'm doing something wrong when including it.
以下是测试代码。由于它使用的是通常的for
循环,因为 ideone 还没有为 C++0x 安装 boost 或者我在包含它时做错了什么。
int main() {
std::vector<int> v1 = {1,2,3,4,5,6};
std::vector<int> v2 = {11,12,13,14,15};
wrapper<int> w(v1,v2);
for(wrapper<int>::iterator it = w.begin(); it != w.end(); ++it)
{
std::cout << *it.it1 <<", "<< *it.it2 << std::endl;
}
return 0;
}
Output:
输出:
1, 11
2, 12
3, 13
4, 14
5, 15
Demo : http://ideone.com/Hf667
This is good for experimentation and learning purpose only, as I don't claim it to be perfect. There can be lots of improvement. And @Steve already has posted boost's solution.
这仅适用于实验和学习目的,因为我并不声称它是完美的。可以有很多改进。@Steve 已经发布了 boost 的解决方案。
回答by daminetreg
Thanks to the answer of Steve Jessop and the great comments, I came up to the following solution, so if you find that nice, vote up Steve Jessop answer first. ;)
感谢 Steve Jessop 的回答和很棒的评论,我想出了以下解决方案,所以如果你觉得不错,请先投票支持 Steve Jessop 的回答。;)
#include <iostream>
#include <vector>
#include <boost/typeof/typeof.hpp>
#include <boost/typeof/std/vector.hpp>
#include <boost/foreach.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/range/iterator_range.hpp>
using namespace boost;
int main(int argc, char **argv) {
std::vector<int> vecFirst = assign::list_of(1)(2)(3)(43)(7)(13);
std::vector<double> vecSecond = assign::list_of(53.45)(-23.545)(0.1574)(1.001)(0.0047)(9.7);
BOOST_AUTO(zipSequence,
make_iterator_range(
make_zip_iterator(make_tuple(vecFirst.begin(), vecSecond.begin())),
make_zip_iterator(make_tuple(vecFirst.end(), vecSecond.end()))
)
);
BOOST_FOREACH( BOOST_TYPEOF(*zipSequence.begin()) each, zipSequence) {
std::cout << "First vector value : " << each.get<0>()
<< " - Second vector value : " << each.get<1>()
<< std::endl;
}
}