2009-04-06 9 views
6

decir que tengo unacumular la suma de los elementos en el mapa, usando el valor

struct SMyStruct 
{ 
    int MULT; 
    int VAL; 

}; 


std::map<std::string, SMyStuct*> _idToMyStructMap; 

Ahora quiero calcular total de todas SMyStuct, en total se define como MULT1 * VAL1 + MULT2 * VAL2 para cada elementos en el idToMyStructMap.

Parece que la función de acumulación es una elección natural. Por favor recomiende. gracias

sin refuerzo por favor .... sólo una 'moda ld STL

+0

Aw, bb, pásenme la respuesta, así que voy a ser un poco pedante en su lugar: sabes que los guiones bajos principales son generalmente una mala idea, ¿no? (reservado para la implementación en la mayoría de los casos) Y el prefijo S en una estructura es un ruido completamente sin sentido. :) – jalf

+0

argh, ok ... Bueno, siempre prefijamos estructuras con S y clases con C; nuestros mandatos estándares de codificación. En cuanto a "_", estoy de acuerdo, pero como no era parte de nada, lo dejé como tal. Normalmente uso m_ para miembros g_ para globales y s_ para estáticos. Gracias por mencionarlo. –

+0

El _ * podría * técnicamente estar bien. Las reglas son algo así como "Double leading _ OR leading _ seguido de mayúsculas está reservado para la implementación. Leading _ seguido de cualquier otra cosa está reservado en el espacio de nombres global".Más fácil de evitar simplemente que conduce _ es del todo;) – jalf

Respuesta

13
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); 
+0

awm, me ganaste con eso. +1 – jalf

+1

Sería más eficiente escribir add_to_totals como un objeto con un operador(). De lo contrario, buena solución. – PaulJWilliams

+0

@Visage, ¿por qué más eficiente? En este caso strucutre no necesita .. – bayda

6

Una variación sobre el tema sería definir operador + para su estructura, y luego sólo tiene que utilizar std :: acumulan en su modo predeterminado.

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

continuación:

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

Por supuesto, si operator+ tiene sentido en general, por su estructura, entonces sería conveniente añadir sobrecargas para el uso de SMyStruct de la izquierda también, y/o hacer las plantillas para que pueda obtener funciones para int, float, double, long, etc. todo de una vez. Como se menciona en jalf en los comentarios, si operator+ (o esta versión) no tiene sentido en general para su estructura, entonces la otra solución es mejor.

+0

1 pero por favor dar un ejemplo de eso :) gracias –

+0

El problema con esto es que ahora tiene un operador +, que es visible a través de su base de código, pero sólo tiene sentido en este contexto específico. Puede ser confuso para cualquiera que lea (o mantenga) el código. – jalf

+0

@jalf - quizás, pero quizás no. En realidad, puede tener sentido en más lugares, no lo sé. Si no es así, entonces es una razón legítima para no elegir esta ruta. –

1

También puede separar la funcionalidad 'tomar segundo de par' de 'calcular MULT * VAL' y 'agregar algo a un acumulador'.

Aunque no necesita impulso para hacer esto, ya crearon una gran cantidad de un marco de programación 'funcional'. Si no puedes usar boost, necesitas un poco de magia de plantilla. No también complicado, sin embargo.

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

Ahora considero que es mejor poner la multiplicación dentro de la clase.

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

Crear un funtor genérico de 'tomar el segundo del par':

// 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; 
    } 
}; 

Esto parece complicado, pero no es más que una forma genérica de decir: 'primero hacer esto, a continuación, hacer eso con el resultado ':

// 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); } 

Y, por último, poner todo en la práctica:

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; 
} 
Cuestiones relacionadas