2009-04-06 5 views
6

dire che ho unaccumulare la somma di elementi nella cartina, utilizzando il valore

struct SMyStruct 
{ 
    int MULT; 
    int VAL; 

}; 


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

Ora voglio calcolare totale di tutte le SMyStuct, dove totale è definita come MULT1 * VAL1 + MULT2 * VAL2 per ogni elementi in idToMyStructMap.

Sembra che la funzione di accumulo sia una scelta naturale. Si prega di suggerire. grazie

No Amplificato per favore .... solo una 'moda ld stl

+0

Aw, bb mi ha battuto per la risposta, quindi sarò un po 'pedante invece: sai che i principali underscore sono generalmente una cattiva idea, giusto? (riservato alla realizzazione nella maggior parte dei casi) E il prefisso S su una struttura è completamente privo di rumore. :) – jalf

+0

argh, ok ... Beh abbiamo sempre prefisso le strutture con S e le classi con C; i nostri mandati standard di codifica. Nella misura in cui "_", sono d'accordo ma poiché non faceva parte di nulla, l'ho lasciato come tale. Solitamente uso m_ per i membri g_ per globals e s_ per static. Grazie per segnalarlo. –

+0

_ * potrebbe * tecnicamente essere ok. Le regole sono qualcosa come "Il doppio comando _ O il comando _ seguito dalla lettera maiuscola è riservato all'implementazione." Il comando _ seguito da ogni altra cosa è riservato nello spazio dei nomi globale ".È più facile evitare semplicemente di condurre _'s complessivamente;) – jalf

risposta

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, mi hai battuto. +1 – jalf

+1

Sarebbe più efficiente scrivere add_to_totals come oggetto con un operatore(). Altrimenti, buona soluzione. – PaulJWilliams

+0

@Visage, perché più efficiente? In questo caso non è necessario strucutre .. – bayda

6

Una variazione sul tema sarebbe definire operatore + per la vostra struct, e poi basta usare std :: si accumulano nel la sua modalità predefinita.

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

Poi:

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

Naturalmente, se operator+ ha un senso, in generale, per la vostra struct, allora che ci si vuole aggiungere sovraccarichi per l'utilizzo SMyStruct a sinistra pure, e/o fare loro modelli in modo da ottenere funzioni per int, float, double, long, ecc. tutto in un colpo solo. Come jalf menzionato nei commenti, se operator+ (o questa versione di esso) non ha senso in generale per la tua struttura, allora l'altra soluzione è migliore.

+0

+1 ma si prega di fornire un esempio di ciò :) grazie –

+0

Il problema è che ora si dispone di un operatore + che è visibile in tutto il codebase, ma ha senso solo in questo specifico contesto. Può essere fonte di confusione per chiunque legga (o mantenga) il codice. – jalf

+0

@jalf - forse, ma forse no. Potrebbe avere senso in più luoghi, non lo so. In caso contrario, è un motivo legittimo per non scegliere questo percorso. –

1

È inoltre possibile separare la funzionalità "Prendi secondo della coppia" da "calcolare MULT * VAL" e "aggiungere qualcosa ad un accumulatore".

Anche se non è necessario potenziare per fare ciò, hanno già creato una grande quantità di un quadro di programmazione "funzionale". Se non puoi usare boost, hai bisogno di un modello magico per conto tuo. Non troppo complicato, tuttavia,.

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

Ora ritengo migliore per mettere la moltiplicazione all'interno della classe.

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

Creare un funtore generico per 'prendere il secondo di coppia':

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

Questo sembra difficile, ma è solo un modo generico per dire: 'prima fare questo, quindi farlo con il risultato ':

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

E, infine, mettere tutto in pratica:

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