using of std::accumulate

╄→гoц情女王★ 提交于 2019-12-31 16:11:28

问题


Need prettier solution of below example but with std::accumulate.

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

class Object
{
public:
    Object( double a, double b ):
        a_( a ),
        b_( b )
    {}

    double GetA() const { return a_; }
    double GetB() const { return b_; }
    // other methods
private:
    double a_;
    double b_;
};

class Calculator
{
public:
    Calculator( double& result ):
        result_( result )
    {}

    void operator() ( const Object& object )
    {
        // some formula
        result_ += object.GetA() * object.GetB();
    }
private:
    double& result_;
};

int main()
{
    std::vector< Object > collection;
    collection.push_back( Object( 1, 2 ) );
    collection.push_back( Object( 3, 4 ) );

    double result = 0.0;
    std::for_each( collection.begin(), collection.end(),
                   Calculator( result ) );

    std::cout << "result = " << result << std::endl;

    return 0;
}

回答1:


do changes in Calculator and main function.

struct Calculator
{
    double operator() ( double result, const Object& obj )
    {
        return result + ( obj.GetA() * obj.GetB());
    }

};

int main()
{
    std::vector< Object > collection;
    collection.push_back( Object( 1, 2 ) );
    collection.push_back( Object( 3, 4 ) );

    double result = std::accumulate( collection.begin(), collection.end(), 0, Calculator() );
    std::cout << "result = " << result << std::endl;

    return 0;
}

also it could be better:

double sumABProduct( double result, const Object& obj )
{
    return result + ( obj.GetA() * obj.GetB());
}

double result = std::accumulate( collection.begin(), collection.end(), 0, sumABProduct );



回答2:


Update 2: Boost.Lambda makes this a piece of cake:

// headers
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
// ...
cout << accumulate(dv.begin(), dv.end(), 
                   0, 
                   _1 += bind(&strange::value, _2)) //strange defined below
     << endl;

Update: This has been bugging me for a while. I can't just get any of the STL algorithms to work in a decent manner. So, I rolled my own:

// include whatever ...
using namespace std;

// custom accumulator that computes a result of the 
// form: result += object.method();
// all other members same as that of std::accumulate
template <class I, class V, class Fn1, class Fn2>
V accumulate2(I first, I last, V val, Fn1 op, Fn2 memfn) {
    for (; first != last; ++first)
        val = op(val, memfn(*first));
    return val;
}

struct strange {
    strange(int a, int b) : _a(a), _b(b) {}
    int value() { return _a + 10 * _b; }
    int _a, _b;
};

int main() {
    std::vector<strange> dv;
    dv.push_back(strange(1, 3));
    dv.push_back(strange(4, 6));
    dv.push_back(strange(20, -11));        
    cout << accumulate2(dv.begin(), dv.end(), 
                        0, std::plus<int>(), 
                        mem_fun_ref(&strange::value)) << endl;
}

Of course, the original solution still holds: The easiest is to implement an operator+. In this case:

double operator+(double v, Object const& x) {
        return v + x.a_;
}

and make it a friend of Object or member (look up why you may prefer one over the other):

class Object
{
   //...
  friend double operator+(double v, Object const& x);

and you're done with:

 result = accumulate(collection.begin(), collection.end(), 0.0);

My earlier approach doesn't work because we need a binary_function.

std::accumulate manual.




回答3:


here is an issue here, I guess the arguments are written in the wrong order should be:

result = std::accumulate(collection.begin(), collection.end(), Object(0),Adapt())
where Adapt is defined thus:

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); }
    static Object operator()(Object const &x, Object const &y) { 
       return Object(mul(x)+mul(y)) ; } };

in this case of accumulate, the result is contained in a returned Object.

If you are using gnu parallel mode the functor will give you problems if the result and the actual object referred to by the iterator are different.

struct Adapt { 
        static double mul(Object const &x) { return x.GetA() * x.GetB(); }
        static double operator()(Object const &x, Object const &y) { 
           return mul(x)+mul(y) ; } };
result = std::accumulate(collection.begin(), collection.end(), 0.0,Adapt())

will not work with gnu parallel mode for some strange and silly reason.




回答4:


Using c++0x:

#include <numeric>
#include <vector>
#include <iostream>

class Object
{
  public:
     Object( double a, double b ):
        a_( a ),
        b_( b )
      {}

    double GetA() const { return a_; }
    double GetB() const { return b_; }
    // other methods
  private:
    double a_;
    double b_;
};

int main()
{
    std::vector< Object > collection;
    collection.push_back( Object( 1, 2 ) );
    collection.push_back( Object( 3, 4 ) );
    double result = std::accumulate( collection.begin(), collection.end(), 0,
                                     [] (double result, const Object& obj) 
                                     {
                                       return result + obj.GetA() * obj.GetB();
                                     }
                                   ); 

   std::cout << "result = " << result << std::endl;

   return 0;
} 



回答5:


One would hope this is homework...

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); }
    static double operator()(Object const &x, Object const &y) { 
       return mul(x)+mul(y); } };

and

result = std::accumulate(collection.begin(), collection.end(), Object(0,0),Adapt() );

assuming you're not allowed to touch the declaration of Object.



来源:https://stackoverflow.com/questions/618472/using-of-stdaccumulate

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!