【问题标题】:STL way to add a constant value to a std::vector将常量值添加到 std::vector 的 STL 方法
【发布时间】:2010-12-16 13:53:34
【问题描述】:

标准库中是否有一种算法可以为 std::vector 的每个元素添加一个值? 类似的东西

std::vector<double> myvec(5,0.);
std::add_constant(myvec.begin(), myvec.end(), 1.);

将值 1.0 添加到每个元素?

如果在 STL 中没有很好的(例如简短、美观、易于阅读)的方式来执行此操作,那么 boost 怎么样?

【问题讨论】:

  • 感谢您的快速回答 - 我编辑了这个问题以更好地代表我真正在寻找的东西 - 一种易于阅读的便携方式来实现这一目标
  • 到目前为止,您的任何一个答案都适用于任何符合 C++03 的编译器。我认为std::add_constant 不存在的原因是因为它很容易编写你自己的。 C++ 不是函数式语言,所以做这样的事情有点笨拙。
  • @Kristo,是的,自己写很容易,但你自己写的不会很快。我正在寻找类似于 BLAS 功能的东西:一个易于阅读的界面隐藏了一个复杂的算法,例如可能使用多线程或其他功能。
  • 对于大型向量,它可能比手动滚动的 for 循环更快,这要归功于编译器内联。要并行化“为每个元素加 1”操作,您将需要一个单独的库或针对您的硬件调整的自定义解决方案。请记住:确保在确定它太慢之前对其进行概要分析。
  • 你应该看看 boost 中的 uBlas 库,boost.org/doc/libs/1_45_0/libs/numeric/ublas/doc/index.htm,也许你会在那里找到有用的东西......

标签: c++ stl


【解决方案1】:

如果使用 C++0x,使用 lambda 函数会更短:

std::for_each(myvec.begin(), myvec.end(), [](double& d) { d+=1.0;});

【讨论】:

    【解决方案2】:

    看看std::for_eachstd::transform。后者接受三个迭代器(序列的开始和结束,以及输出序列的开始)和一个函数对象。有几种方法可以写这个。一种方法,只使用标准的东西,是:

    transform(myvec.begin(), myvec.end(), myvec.begin(),
              bind2nd(std::plus<double>(), 1.0));              
    

    您也可以使用for_each 来执行此操作,但std::plus 的默认行为不会将答案写回原始向量。在这种情况下,您必须编写自己的函子。简单示例如下:

    struct AddVal
    {
        double val;
        AddVal(double v) : val(v);
    
        void operator()(double &elem) const
        {
            elem += v;
        }
    };
    
    std::for_each(myvec.begin(), myvec.end(), AddVal(1.0));
    

    【讨论】:

    • 速度很快! :) 我来晚了,所以让我放弃cplusplus.com/reference/algorithm/transform
    • 酷。也比我快。正如页面所说,甚至比 OP 还要快! “1 分钟前询问”、“2 分钟前回答”
    • @Kos,当我输入更完整的答案时,OP 也会立即开始工作。
    • std::bind2nd 自 C++11 起已弃用,并将在 C++17 中删除。考虑std::transform(myvec.begin(), myvec.end(), myvec.begin(), [&amp;](double x){x+1.0;});
    • @Paamand:稍微更正以包含返回:std::transform(myvec.begin(), myvec.end(), myvec.begin(), [&amp;](double x){return(x+1.0);});
    【解决方案3】:

    普通 C++0X 中最短的方法是:

    for(double& d : myvec)
      d += 1.0;
    

    还有提升:

    for_each(myvec, _1 += 1.0); // boost.range + boost.lambda
    

    【讨论】:

    • 非常好的答案!
    【解决方案4】:
    std::transform( myvec.begin(), myvec.end(), 
                    myvec.begin(), std::bind2nd( std::plus<double>(), 1.0 ) );
    

    【讨论】:

    • 你比我早了 30 多岁,我已经删除了我的答案! :)
    • 你也可以使用 lambda 作为仿函数:like []( double x ) { return x + 1.0; } 如果你有 c++0x,或者 boost::bind( std::plus(), _1, 1.0 )
    • 有趣的打字保护程序:感谢Koenig Lookup,您可以消除代码中除了最里面的std:: 之外的所有内容,它仍然可以工作。
    【解决方案5】:

    如果您有兴趣在向量上执行大量数学运算,您可能需要查看标准库的 &lt;valarray&gt; 部分。它基本上是为矢量数值计算(切片、数学函数、逐点运算符等)而设计的std::vector&lt;&gt;

    真正糟糕的唯一部分是它与std::vector&lt;&gt; 之间的转换并不容易。

    【讨论】:

    • Valarray ftw!它对数学相关的东西的关注太少了。
    • @rubenvb:确实,它是库中最不为人知的部分之一。不幸的是,界面对于任何不是数学的东西都很笨拙。标准礼让至少可以添加迭代器和范围构造函数,以便轻松转换到其他容器/从其他容器转换。
    【解决方案6】:

    最好的方法是添加std::transform()和lambda表达式。

    #include <vector>
    #include <algorithm>    
    std::vector<double> myVector;
    double constantElement;
    std::transform(myVector.begin(), myVector.end(), myVector.begin(), [&](auto& value){ return value+constantElement; });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-22
      • 2018-08-16
      • 2016-04-06
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多