【问题标题】:How can I iterate over two vectors simultaneously using BOOST_FOREACH?如何使用 BOOST_FOREACH 同时迭代两个向量?
【发布时间】:2011-11-09 08:20:58
【问题描述】:

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

【问题讨论】:

标签: c++ boost iterator boost-foreach


【解决方案1】:

同时迭代两件事被称为“zip”(来自函数式编程),Boost has a zip iterator

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 而不是 boost::tuple

我想既然doSomething 可能有参数(int&amp;, int&amp;),实际上我们想要一个tuple&lt;int&amp;,int&amp;&gt;。希望它有效。

【讨论】:

  • 非常好,不知道 zip 迭代器(从不需要它:-))。 +1
  • @Vlad:我也没有,但只要你知道它叫做“zip”,并且盲目相信任何你能想到的东西,Boost 已经有了,Google 就是你的朋友 :-)
  • 我从来没有做过函数式编程,所以我什至没有听说过“zip”(除非我们谈论压缩)。很高兴知道。
  • ..或者他可以只是std:make_pair(beg, end),因为 BOOST_FOREACH 也接受这些作为范围。 (其中begmake_zip_iterator(make_tuple(v1.begin(), v2.begin())
  • @Cubbi:好点,我忘了。而std::make_pair(beg, end);boost::iterator_range(beg, end); 略短。
【解决方案2】:

如果用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 没有记录。无论如何,对我有用。

【讨论】:

【解决方案3】:

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

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

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 没有为 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;
}

输出:

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

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

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

【讨论】:

    【解决方案4】:

    感谢史蒂夫杰索普和伟大的 cmets 的回答,我想出了以下解决方案,所以如果你觉得很好,请先投票给史蒂夫杰索普的答案。 ;)

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

    【讨论】:

      猜你喜欢
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      • 2017-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多