накапливать сумму элементов в карте, используя значение - PullRequest
6 голосов
/ 06 апреля 2009

скажи, у меня есть

struct SMyStruct 
{
   int MULT;
   int VAL;

};


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

Теперь я хочу вычислить сумму всех SMyStuct, где сумма определяется как MULT1 * VAL1 + MULT2 * VAL2 для каждого элемента в idToMyStructMap.

Кажется, что функция накопления является естественным выбором. Пожалуйста, предложите. спасибо

Не буст, пожалуйста .... просто модный стиль

Ответы [ 3 ]

13 голосов
/ 06 апреля 2009
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 );
6 голосов
/ 06 апреля 2009

Разновидностью темы может быть определение оператора + для вашей структуры, а затем просто использовать std :: аккумулирование в режиме по умолчанию.

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

Тогда:

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

Конечно, если operator+ имеет смысл в целом для вашей структуры, то вы захотите добавить перегрузки для использования SMyStruct также слева и / или сделать их шаблонами, чтобы вы получали функции для int, float двойной, длинный и т. д. все в одном кадре. Как отметил Джальф в комментариях, если operator+ (или эта версия) не имеет смысла для вашей структуры в целом, тогда другое решение лучше.

1 голос
/ 06 апреля 2009

Вы также можете отделить функцию «занять вторую пару» от «вычислить MULT * VAL» и «добавить что-то в аккумулятор».

Несмотря на то, что вам не нужно повышать, чтобы сделать это, они уже создали большую часть «функциональной» среды программирования. Если вы не можете использовать boost, вам понадобится собственный шаблон магии. Не слишком сложно, хотя.

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

Теперь я считаю, что лучше поместить умножение в класс.

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

Создайте универсальный функтор для '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;
  }
};

Это выглядит сложно, но это просто общий способ сказать: «сначала сделай это, а затем сделай это с результатом»:

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

И, наконец, воплощение всего этого в жизнь:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...