如何使用 BOOST_FOREACH 同时迭代两个向量?

发布于 2024-12-02 11:06:09 字数 285 浏览 2 评论 0原文

我想用 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 );
}

I'd like to replicate the following with 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 );
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

囍孤女 2024-12-09 11:06:09

同时迭代两个事物称为“zip”(来自函数式编程),并且 Boost 有一个 zip 迭代器

zip 迭代器提供了并行迭代多个
同时控制序列。构建了 zip 迭代器
来自迭代器元组。移动 zip 迭代器会移动所有
并行迭代器。取消引用 zip 迭代器会返回一个元组
其中包含取消引用各个迭代器的结果。

请注意,它是一个迭代器,而不是范围,因此要使用 BOOST_FOREACH,您必须将其中两个填充到 iterator_rangepair。所以它不会很漂亮,但是稍微小心一点,您可能可以想出一个简单的 zip_range 并编写:

BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
    doSomething(p.get<0>(), p.get<1>());
}

或者 2 的特殊情况并使用 std::pair code> 而不是 boost::tuple。

我想,由于 doSomething 可能有参数 (int&, int&),实际上我们想要一个 tuple 。希望它有效。

Iterating over two things simultaneously is called a "zip" (from functional programming), and Boost has a zip iterator:

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.

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_range or 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(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.

I suppose that since doSomething might have parameters (int&, int&), actually we want a tuple<int&,int&>. Hope it works.

落在眉间の轻吻 2024-12-09 11:06:09

如果你使用 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

奇怪的部分是 boost::combine 没有记录。无论如何,对我有用。

If you use boost, I think it should be as simple as:

#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.

我的奇迹 2024-12-09 11:06:09

如果您想使用 BOOST_FOREACH 同时迭代两个向量,就像您在示例代码中所做的那样,那么您必须将这两个向量封装在一个包装类中,该类应该公开 begin 和 end 函数。这些函数返回自定义迭代器,用于迭代包装器,包装器内部将迭代两个向量。听起来不太好,但这就是你必须做的。

这是我第一次尝试实现这个(最小实现只是为了演示基本思想):

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_;
    }    
};

以下是测试代码。因为它使用通常的 for 循环,因为 ideone 尚未安装 for boost for C++0x 或者我在包含它时做错了什么。

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;
}

输出:

1, 11
2, 12
3, 13
4, 14
5, 15

演示: http://ideone.com/Hf667

这仅适用于实验和学习目的,因为我没有声明它做到完美。可以有很多改进。 @Steve 已经发布了 boost 的解决方案。

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.

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.

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.

套路撩心 2024-12-09 11:06:09

感谢 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;
    }
}

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. ;)

#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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文