以元素方式添加两个范围的惯用且有效的方法

时间:2013-09-17 18:44:14

标签: c++ algorithm c++11 stl

是否有任何有效且惯用的方式来执行以下操作?

std::vector<int> a = { 1, 2, 3, 4 };
std::vector<int> b = { 5, 6, 7, 8 };

for (std::size_t i = 0 ; i < a.size() ; ++i)
{
    a[i] += b[i];
}

我试图避免括号/索引表示法,只使用迭代器,以便操作与任何具有前向迭代器的容器一起使用。我想到了以下解决方案:

std::vector<int> a = { 1, 2, 3, 4 };
std::vector<int> b = { 5, 6, 7, 8 };

std::transform(a.begin(), a.end(),
               b.begin(),
               a.begin(),
               std::plus<int>());

但是,a.begin()存在冗余,我只能使用+而不是+=。标准库中是否有一些算法允许我使用迭代器而没有任何冗余,或者我是否必须手动编写完整的循环?

6 个答案:

答案 0 :(得分:8)

也许某些事情本来是惯用的,但从来没有做过:

std::valarray<int> a = { 1, 2, 3, 4 };
std::valarray<int> b = { 5, 6, 7, 8 };

现在你可以做这些

std::valarray<int> c = a + b; //apply '+' element-wise; store result in c

a += b;  //apply '+=' element-wise 

有关详细信息,请参阅documentation of std::valarray

答案 1 :(得分:4)

如果您不止一次使用它,并且您对标准库的精神中的简单界面感兴趣,您可以为特定用例创建一个简单的模板类(我将其称为“范围增量” “),写下类似的东西:

#include<vector>
#include<algorithm>
#include<iostream>

template<typename InputIt>
InputIt range_increment(InputIt dbeg, InputIt dend, InputIt sbeg) {
  while(dbeg!=dend) {
    *(dbeg++) += (*sbeg++);
  }
  return dbeg;
}

int main() {
  std::vector<int> a = { 1, 2, 3, 4 };
  std::vector<int> b = { 5, 6, 7, 8 };

  range_increment(a.begin(), a.end(), b.begin());

  for(auto x:a) {
    std::cout<<x<<std::endl;
  }
}

哪个收益率:

6
8
10
12

答案 2 :(得分:3)

a.begin()的冗余有什么问题?

如果您对此不满意,请创建自己的算法:transform_inplace

template <class InputIterator, class OutputIterator, class BinaryOperator>
OutputIterator transform_inplace (InputIterator first,
                                  InputIterator last,
                                  OutputIterator result,
                                  BinaryOperator op)
{
  while (first != last) {
    *result = op(*result, *first);
    ++result; 
    ++first;
  }
  return result;
}

答案 3 :(得分:2)

不确定我称之为“惯用语”,但是:

assert(a.size()==b.size());
auto bi = b.begin();
for (auto& i : a) {
  i += *(bi++);
}

非常简洁。

答案 4 :(得分:1)

我找不到我正在寻找的通用函数,最后使用了我命名为range_map的以下函数(“使用两个给定范围映射给定函数元素”)。正如评论所指出的,它实际上只不过是二进制std::for_each

template<class InputIt1, class InputIt2, class BinaryOperation>
void range_map(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, BinaryOperation binary_op)
{
    while (first1 != last1) {
        binary_op(*first1++, *first2++);
    }
}

我通过以下方式创建了课程plus_assign

template<typename T>
struct plus_assign
{
    void operator()(T &lhs, const T &rhs) const 
    {
        lhs += rhs;
    }
};

然后我的代码变成了:

std::vector<int> a = { 1, 2, 3, 4 };
std::vector<int> b = { 5, 6, 7, 8 };

range_map(a.begin(), a.end(),
          b.begin(),
          plus_assign<int>());

还有函数range_map的一元对应物,用于将给定的仿函数映射到范围:

template<class InputIt, class BinaryOperation>
void range_map(InputIt first, InputIt last,
               UnaryOperation unary_op)
{
    while (first != last) {
        unary_op(*first1++);
    }
}

答案 5 :(得分:0)

使用运算符重载

#include <vector>

std::vector<int>& operator += (std::vector<int>& a, std::vector<int> const& b)
{
    for(size_t i = 0; i != a.size(); ++i)
        a[i] += b[i];

    return a;
}

int main(int argc, char * argv[])
{
   std::vector<int> a { 1, 3, 5, 7, 9};
   std::vector<int> b { 2, 4, 6, 8, 10};

   a += b;

   return 0;
}