【问题标题】:Multiply vector elements by a scalar value using STL使用 STL 将向量元素乘以标量值
【发布时间】:2011-04-22 13:19:52
【问题描述】:

您好,我想(乘、加等)向量按标量值,例如 myv1 * 3,我知道我可以使用 forloop 执行函数,但是有没有使用 STL 函数的方法? {Algorithm.h :: 变换函数}之类的东西?

【问题讨论】:

    标签: c++ stl vector element operation


    【解决方案1】:

    是的,使用std::transform

    std::transform(myv1.begin(), myv1.end(), myv1.begin(),
                   std::bind(std::multiplies<T>(), std::placeholders::_1, 3));
    

    在 C++17 之前,您可以使用 std::bind1st(),它在 C++11 中已被弃用。

    std::transform(myv1.begin(), myv1.end(), myv1.begin(),
                   std::bind1st(std::multiplies<T>(), 3));
    

    对于占位符;

    #include <functional> 
    

    【讨论】:

    • 对第一个示例中 std::bind() 所做的任何说明?
    • 预计这会比循环更快吗?
    【解决方案2】:

    如果您可以使用valarray 而不是vector,则它具有用于进行标量乘法的内置运算符。

    v *= 3;
    

    如果您必须使用vector,您确实可以使用transform 来完成这项工作:

    transform(v.begin(), v.end(), v.begin(), _1 * 3);
    

    (假设您有类似于Boost.Lambda 的东西,可以让您轻松创建匿名函数对象,例如_1 * 3 :-P)

    【讨论】:

    • Valarrays 是 IMO 的正确解决方案。幸运的是,您的实现使用 SSE 指令来实现该过程,从而显着加快了速度。请参阅pixelglow.com/macstl/valarray 了解 valarray 的一种此类实现。不幸的是,它不是很普遍,所以如果你想要 SSE 指令的优势,你可能不得不使用编译器内在函数......
    • @Dragon:valarray 是最好的 STL 解决方案,但它对于高性能计算不是很好,因为它倾向于大量复制内存中的数据,并产生包含单个操作的小循环序列内存访问模式较差。不过,从valarray 升级到合适的表达式模板系统更容易。
    【解决方案3】:

    为您的问题提供现代 C++ 解决方案。

    std::vector<double> myarray;
    double myconstant{3.3};
    std::transform(myarray.begin(), myarray.end(), myarray.begin(), [&myconstant](auto& c){return c*myconstant;});
    

    【讨论】:

    • 我会让它变得更简单,只是一个空的捕获 lambda,并获得 const 对象。毕竟,这个 id 应该是 Kickstarter。
    【解决方案4】:

    我认为for_each 非常适合您想要遍历向量并根据某种模式操作每个元素,在这种情况下,一个简单的 lambda 就足够了:

    std::for_each(myv1.begin(), mtv1.end(), [](int &el){el *= 3; });
    

    请注意,您想要捕获以供 lambda 函数使用的任何变量(例如,您想要与某个预定的标量相乘),都将作为参考放入括号中。

    【讨论】:

    • 这不是std::for_each的目的。 std::for_each 将一些(可能是有状态的)函数对象应用于一个范围,然后返回这个函数对象。如果您想转换范围,请使用std::transform 以使您的意图更加清晰。
    【解决方案5】:

    如果您必须将结果存储在 新向量 中,那么您可以使用 &lt;algorithm&gt; 标头中的 std::transform()

    #include <algorithm>
    #include <vector>
    
    int main() {
        const double scale = 2;
        std::vector<double> vec_input{1, 2, 3};
        std::vector<double> vec_output(3); // a vector of 3 elements, Initialized to zero
        // ~~~
        std::transform(vec_input.begin(), vec_input.end(), vec_output.begin(),
                       [&scale](double element) { return element *= scale; });
        // ~~~
        return 0;
    }
    

    所以,我们在这里要说的是,

    • vec_input的值(elements)从开头(vec_input.begin())到结尾(vec_input.begin()),
      • 基本上,使用前两个参数,您可以指定要转换的元素范围 ([beginning, end)), 范围
    • 将每个element 传递给最后一个参数,lambda 表达式,
    • 把lambda表达式的输出放到vec_output从头开始(vec_output.begin())。
      • 第三个参数是指定目标向量的开始。

    lambda 表达式

    • 通过引用从外部捕获比例因子 ([&amp;scale]) 的值,
    • 将 double 类型的向量元素作为其输入(由 std::transform() 传递给它)
    • 在函数体中,它返回最终结果,
      • 正如我上面提到的,它将因此存储在vec_input中。

    最后说明:虽然没有必要,但您可以按以下方式传递 lambda 表达式:

    [&scale](double element) -> double { return element *= scale; }
    

    它明确指出 lambda 表达式的输出是双精度数。但是,我们可以省略它,因为在这种情况下,编译器可以自行推断返回类型。

    【讨论】:

      【解决方案6】:

      我知道这不是您想要的 STL,但您可以根据不同的需求进行调整。

      以下是您可以用来计算的模板; 'func' 将是您想要执行的函数:乘法、加法等; 'parm' 是 'func' 的第二个参数。您可以轻松地扩展它以使用更多不同类型的参数来获取不同的函数。

      template<typename _ITStart, typename _ITEnd, typename _Func , typename _Value >
      _ITStart xform(_ITStart its, _ITEnd ite, _Func func, _Value parm)
      {
          while (its != ite) { *its = func(*its, parm); its++; }
          return its;
      }
      ...
      
      int mul(int a, int b) { return a*b; }
      
      vector< int > v;
      
      xform(v.begin(), v.end(), mul, 3); /* will multiply each element of v by 3 */
      

      此外,这不是一个“安全”功能,您必须在使用前进行类型/值检查等。

      【讨论】:

      • 这行得通,但本质上是在重新发明轮子,因为std::transform 已经为您做到了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      • 2010-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多