Accumulate the amount of elements on the map using the value

Let's say i have

struct SMyStruct { int MULT; int VAL; }; std::map<std::string, SMyStuct*> _idToMyStructMap; 

Now I want to calculate the total number of all SMyStucts, where total is defined as MULT1 * VAL1 + MULT2 * VAL2 for each element in idToMyStructMap.

The accumulation function seems to be a natural choice. Please suggest. thanks

No Boost please .... just 'ld fashion stl

+6
c ++ algorithm stl
source share
3 answers
 typedef std::map< std::string, SMyStruct* > string_to_struct_t; int add_to_totals( int total, const string_to_struct_t::value_type& data ) { return total + data.second->MULT * data.second->VAL; } const int total = std::accumulate( _idToMyStructMap.begin(), _idToMyStructMap.end(), 0, add_to_totals ); 
+13
source share

The theme variant will define the + operator for your structure, and then just use std :: accumulate in its default mode.

 int & operator+ (const int &lhs, const SMyStruct &rhs){ return lhs + (rhs.MULT * rhs.VALUE); } 

Then:

 std::accumulate(_idToMyStructMap.begin(), _idToMyStructMap.end(), 0); 

Of course, if operator+ makes sense at all for your structure, then you want to add overloads to use SMyStruct on the left as well and / or make them templates so that you get functions for int, float, double, long, etc. all in one shot. As stated in the comments, if operator+ (or this version) does not make sense at all for your structure, then another solution is better.

+6
source share

You can also separate the “take a second pair” function from “calculate MULT * VAL” and “add something to the battery”.

Despite the fact that you do not need momentum for this, they have already created many functional software frameworks. If you cannot use boost, you need template magic. However, not too difficult.

 #include <map> #include <algorithm> #include <numeric> #include <functional> #include <iostream> 

Now I think it's better to put the multiplication inside the class.

 struct SMyStruct { int MULT; int VAL; long f() const { return MULT*VAL; } }; 

Create a generic functor for 'take second of pair':

 // a 'take-second' functor template< typename at_pair > struct to_second_t : public std::unary_function< at_pair, typename at_pair::second_type > { const typename at_pair::second_type& operator()( const at_pair & p ) const { return p.second; } }; 

It looks complicated, but it’s just a general way of saying, “First do it and then do it with the result”:

 // compose two functors (simplified) template< typename at_F, typename at_G > struct compose_t : public std::unary_function< typename at_F::argument_type, typename at_G::result_type >{ at_F f; at_G g; compose_t( at_F& f, at_G& g ): f( f ), g(g) {} typename at_G::result_type operator()( const typename at_F::argument_type& v ) const { return g( f( v ) ); } }; template< typename at_F, typename at_G > compose_t<at_F, at_G> compose( at_F& f, at_G& g ) { return compose_t<at_F,at_G>( f, g ); } // compose two functors (a unary one, and a binary one) // template< typename at_F, typename at_G > struct compose2_t : public std::binary_function< typename at_F::first_argument_type, typename at_G::argument_type, typename at_G::result_type >{ at_F f; at_G g; compose2_t( at_F& f, at_G& g ): f( f ), g(g) {} typename at_G::result_type operator()( const typename at_F::first_argument_type& a1, const typename at_G::argument_type& v ) const { return f( a1, g( v ) ); } }; template< typename at_F, typename at_G > compose2_t<at_F, at_G> compose2( at_F& f, at_G& g ) { return compose2_t<at_F,at_G>( f, g ); } 

And finally, all this in practice:

 int main() { typedef std::map<int, SMyStruct > tMap; tMap m; SMyStruct s = {1,2}; m[1].VAL = 1; m[1].MULT = 3; m[2].VAL = 2; m[2].MULT = 10; m[3].VAL = 3; m[3].MULT = 2; // mind, this is not LISP (yet) long total = std::accumulate( m.begin(), m.end(), 0, compose2( std::plus<int>(), compose( to_second_t<tMap::value_type>(), std::mem_fun_ref( &SMyStruct::f ) ) ) ); std::cout << "total: " << total <<std::endl; return 0; } 
+1
source share

All Articles