2009-04-06 36 views
6

Nói rằng tôi có mộttích lũy tổng của các yếu tố trong bản đồ, sử dụng giá trị

struct SMyStruct 
{ 
    int MULT; 
    int VAL; 

}; 


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

Bây giờ tôi muốn tính tổng của tất cả các SMyStuct, nơi tổng được định nghĩa là MULT1 * VAL1 + MULT2 * VAL2 cho mỗi yếu tố trong idToMyStructMap.

Có vẻ như chức năng tích lũy là một lựa chọn tự nhiên. Xin đề nghị. nhờ

Không Boost xin vui lòng .... chỉ là một 'ld thời trang stl

+0

Aw, bb đánh tôi với câu trả lời, vì vậy tôi sẽ có một chút cảm giác thay thế: Bạn biết dấu gạch dưới hàng đầu nói chung là một ý tưởng tồi, phải không? (dành riêng cho việc thực hiện trong hầu hết các trường hợp) Và tiền tố S trên một cấu trúc là tiếng ồn hoàn toàn vô nghĩa. :) – jalf

+0

argh, ok ... Vâng, chúng tôi luôn luôn tiền tố cấu trúc với S và các lớp học với C; nhiệm vụ tiêu chuẩn mã hóa của chúng tôi. Tức là "_", tôi đồng ý nhưng vì nó không phải là một phần của bất cứ điều gì, tôi để nó như vậy. Tôi thường sử dụng m_ cho các thành viên g_ cho globals và s_ cho tĩnh. Cảm ơn đã chỉ ra điều đó. –

+0

Các _ * có thể * về mặt kỹ thuật là ok. Các quy tắc là một cái gì đó như "Double hàng đầu _ OR hàng đầu _ theo sau là lá thư vốn được dành riêng cho việc thực hiện. Dẫn đầu _ theo sau là bất cứ điều gì khác được dành riêng trong không gian tên toàn cầu".Dễ nhất để tránh hoàn toàn dẫn đầu _) – jalf

Trả lời

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, bạn đánh bại tôi với nó. +1 – jalf

+1

Sẽ hiệu quả hơn khi viết add_to_totals làm đối tượng với toán tử(). Nếu không, giải pháp tốt. – PaulJWilliams

+0

@Visage, tại sao hiệu quả hơn? Trong trường hợp này strucutre không cần .. – bayda

6

Một biến thể của chủ đề sẽ được xác định operator + cho struct của bạn, và sau đó chỉ cần sử dụng std :: tích tụ trong chế độ mặc định của nó.

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

Sau đó:

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

Tất nhiên, nếu operator+ làm cho tinh thần nói chung cho struct của bạn, sau đó bạn muốn thêm quá tải cho việc sử dụng SMyStruct ở bên trái là tốt, và/hoặc chúng mẫu để bạn có được chức năng cho int, phao, đôi, dài, vv tất cả trong một shot. Như jalf được đề cập trong các ý kiến, nếu operator+ (hoặc phiên bản này của nó) không có ý nghĩa nói chung cho cấu trúc của bạn, sau đó giải pháp khác là tốt hơn.

+0

+1 nhưng xin vui lòng cung cấp một ví dụ về điều đó :) cảm ơn –

+0

Vấn đề với điều đó là bây giờ bạn có một toán tử + được hiển thị trong toàn bộ codebase của bạn, nhưng chỉ có ý nghĩa trong ngữ cảnh cụ thể này. Có thể gây nhầm lẫn cho bất kỳ ai đọc (hoặc duy trì) mã. – jalf

+0

@ jalf - có lẽ, nhưng có lẽ không. Nó có thể thực sự có ý nghĩa ở nhiều nơi hơn, tôi không biết. Nếu không, thì đó là lý do chính đáng để không chọn con đường này. –

1

Bạn cũng có thể tách chức năng 'lấy giây ghép nối' khỏi 'tính toán MULT * VAL' và 'thêm thứ gì đó vào bộ tích lũy'.

Mặc dù bạn không cần tăng cường để làm điều này, họ đã tạo ra rất nhiều khung công tác lập trình 'chức năng'. Nếu bạn không thể sử dụng tăng, bạn cần một số mẫu ma thuật của riêng bạn. Tuy nhiên, không phải quá phức tạp.

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

Bây giờ tôi xét thấy tốt hơn để đưa các nhân bên lớp.

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

Tạo một functor chung cho 'mất thứ hai của cặp':

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

này trông khôn lanh, nhưng chỉ đơn thuần là một cách chung chung nói: 'đầu tiên làm điều này, sau đó làm điều đó với kết quả ':

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

Và cuối cùng, đặt nó tất cả trong thực tế:

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; 
} 
Các vấn đề liên quan