【问题标题】:C++ add constant to slice of vectorC ++将常量添加到向量切片
【发布时间】:2019-05-01 09:03:13
【问题描述】:

我知道transform 我可以像这样向某个向量添加一个常量:

std::vector<int> a(3, 2);
std::transform( a.begin(), a.end(), a.begin(), std::bind2nd( std::plus<double>(), 1 ) );

我想知道如何修改transform 以将常量添加到向量的某个切片[index:end],例如最后两个元素。

我可以通过循环来做到这一点,例如:

for (int i=1; i < a.size(); i++) {
    a.at(i) += 1;
}

但也许有更好的选择

【问题讨论】:

  • 我也试过了,但奇怪的是产生3 3 2而不是2 3 3
  • 抱歉,您需要同时添加两个开始迭代器。
  • 您如何认为您的 for 循环不是最佳的,即。你想以什么方式让它变得更好?以后更容易理解吗?让未来的开发人员阅读您的代码更容易理解?只是更少的代码?编译器优化后效率更高?
  • 我不知道,我对 C++ 不是很熟悉,我读过一个应该使用 &lt;vector&gt; 库...不确定这是否包括使用 transform 以及 @hyde
  • @eok 它没有,标准算法的重点是它们是通用的。他们可以使用许多不同列表类型的迭代器,包括但不限于std::vectorstd::liststd::array 等...

标签: c++ vector addition


【解决方案1】:

只是最后一个N 元素?使用反向迭代器:

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

int main() {
  std::vector<int> a(3, 2);
  std::transform(a.rbegin(), std::next(a.rbegin(), 2), a.rbegin(),
                 [](auto n) { return n + 1; });

  for (auto n : a) {
    std::cout << n << '\n';
  }
  return 0;
}

(如果您出于某种原因需要将a 更改为没有随机迭代器的容器类型,使用std::next() 而不仅仅是a.rbegin() + 2 会更容易。)

【讨论】:

    【解决方案2】:

    算法采用迭代器而不是容器的原因正是针对这种情况。

    适应 Python 样式切片的一般方法是将 +ve 值添加到 begin-veend。假设至少有两个元素,增加最后两个元素将是

    auto start = a.end() - 2;
    auto finish = a.end();
    std::transform( start, finish , start, std::bind2nd( std::plus<double>(), 1 ) );
    

    【讨论】:

    • bind2nd 在 C++11 中已弃用并在 C++17 中删除。
    【解决方案3】:

    小重构后的相同代码:

    std::vector< int > a(3, 2);
    
    auto start = a.begin();
    auto end   = a.end();
    auto func  = [](auto val) {
        return val + 1;
    };
    
    std::transform(start, end, start, func);
    

    现在通过修改startend的值,只能修改切片。

    为此可以使用std::advance

    std::advance(start, 1);
    std::advance(end, -1);
    

    在上面的代码中:

    • start 是开头之后的 1 个元素(第 2 个元素 - 索引为 1 的元素)。
    • end 距离末尾有 1 个元素。

    【讨论】:

      【解决方案4】:

      您可以使用跨度(C++20 中的std::span,更早的gsl::span)来表示您的切片。如果您不了解跨度,请查看:

      What is a "span" and when should I use one?

      所以如果你写,

      // ... vector a gets defined
      auto slice = std::span(a).subspan(some_index);
      

      切片现在的行为就像任何标准库容器一样。具体来说,你可以这样写:

      std::transform(slice.begin(), slice.end(), slice.begin(), [](auto v) { return v + 1; });
      

      【讨论】:

      • 有了推导指南,我觉得make... 函数已经不需要了。
      猜你喜欢
      • 2018-10-25
      • 1970-01-01
      • 2018-04-06
      • 1970-01-01
      • 2012-04-27
      • 2018-04-26
      • 1970-01-01
      • 1970-01-01
      • 2014-06-10
      相关资源
      最近更新 更多