2010-07-08 23 views
10

Hãy nói rằng tôi có các đối tượng sau đây:Cách tốt nhất để tổng hợp kết quả của hàm thành viên cho tất cả các phần tử trong vùng chứa là gì?

struct Foo 
{ 
    int size() { return 2; } 
}; 

gì là cách tốt nhất (duy trì nhất, dễ đọc, vv) để có được tổng size của tất cả các đối tượng trong một vector<Foo>? Tôi sẽ đăng giải pháp của mình nhưng tôi quan tâm đến những ý tưởng tốt hơn.

Cập nhật:

Cho đến nay chúng ta có:

  • std :: tích lũy và một functor
  • std :: tích lũy và một biểu thức lambda
  • đồng bằng ol' cho vòng lặp

Có giải pháp khả thi nào khác không? Bạn có thể tạo điều gì đó có thể bảo trì bằng cách sử dụng boost::bind hoặc std::bind1st/2nd không?

+3

'std :: vector vec; vec.size() * 2', vì chúng ta biết rằng 'Foo :: size' luôn trả về 2. :) – jalf

Trả lời

23

Ngoài đề nghị của riêng bạn, nếu trình biên dịch của bạn hỗ trợ C++ 0x biểu thức lambda, bạn có thể sử dụng phiên bản này ngắn hơn:

std::vector<Foo> vf; 

// do something to populate vf 


int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           [](int sum, const Foo& elem){ return sum + elem.size();}); 
+0

typo: dấu chấm phẩy bị thiếu ở cuối phần thân của lambda (tôi không thể chỉnh sửa bản thân mình). – rafak

7

Sử dụng std::accumulate và hàm functor.

#include <functional> 
#include <numeric> 

struct SumSizes : public std::binary_function<int, Foo, int> 
{ 
    int operator()(int total, const Foo& elem) const 
    { 
     return total + elem.size(); 
    } 
}; 

std::vector<Foo> vf; 

// do something to populate vf 

int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           SumSizes()); 
+0

Giải pháp của bạn là một thành ngữ đơn nhất, tất nhiên, nhưng một vòng lặp lặp câm có thể dễ dàng hơn trong những trường hợp đơn giản như vậy. – Philipp

+0

+1 Điều này sẽ được cải thiện bằng cách templating 'SumSizes' cho genericity, vì tất cả các thùng chứa tiêu chuẩn có một' size() 'thành viên chức năng. –

+0

@Jon, tôi nghĩ bạn có thể đã hiểu nhầm câu hỏi. Điểm không phải là để có được kích thước của container, nhưng để tổng hợp kết quả của một hàm thành viên của tất cả các phần tử. Có lẽ 'size' là một cái tên nghèo nàn cho một chức năng như vậy. –

4

Dưới đây là giải pháp down-to-earth:

typedef std::vector<Foo> FooVector; 
FooVector vf; 
int totalSize = 0; 
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) { 
    totalSize += it->size(); 
} 
+0

Dễ đọc hơn nhiều so với các giải pháp chức năng khác. – Jon

7

Tôi tìm thấy các trình tăng tốc của bộ lặp tăng cường, mặc dù chúng có thể hơi dài dòng (các thuật toán dựa trên dải ô sẽ làm cho điều này tốt hơn). Trong trường hợp này transform iterators có thể thực hiện công việc:

#include <boost/iterator/transform_iterator.hpp> 
//... 

int totalSize = std::accumulate(
    boost::make_transform_iterator(vf.begin(), std::mem_fn(&Foo::size)), 
    boost::make_transform_iterator(vf.end(), std::mem_fn(&Foo::size)),0); 

Chỉnh sửa: thay thế "boost::bind(&Foo::size,_1)" bởi "std::mem_fn(&Foo::size)"

Chỉnh sửa: Tôi chỉ thấy rằng thư viện Boost.Range đã được cập nhật để giới thiệu các thuật toán phạm vi! Đây là một phiên bản mới của giải pháp giống nhau:

#include <boost/range/distance.hpp> // numeric.hpp needs it (a bug?) 
#include <boost/range/numeric.hpp> // accumulate 
#include <boost/range/adaptor/transformed.hpp> // transformed 
//... 
int totalSize = boost::accumulate(
    vf | boost::adaptors::transformed(std::mem_fn(Foo::size)), 0); 

Lưu ý: các buổi biểu diễn là xấp xỉ như nhau (xem nhận xét của tôi): trong nội bộ, sử dụng transformedtransorm_iterator.

+1

Tôi đã làm timings so sánh giải pháp này và giải pháp trực tiếp, và tiếc là giải pháp này chậm hơn (tôi đã tìm thấy hệ số từ 2 đến 5). Tuy nhiên điều này có thể không phải là một mối quan tâm. – rafak

+0

Tôi nghĩ đây là câu trả lời hay nhất. Vấn đề là ** những gì ** để tích lũy, được giải quyết bởi một iterator tùy chỉnh, không ** làm thế nào ** để tích lũy, được giải quyết bằng cách sử dụng một functor. Hành vi tích lũy mặc định (cộng) _is_ những gì bạn muốn. Xem xét việc mở rộng vấn đề này cho sản phẩm bên trong: trình biến đổi được chuyển đổi có thể tái sử dụng trong khi hàm functor thì không. Một hàm functor mới cho mọi thuật toán sẽ được yêu cầu đơn giản để xác định lại hành vi mặc định về kích thước thành viên(). –

4

sử dụng C++ 11 (và xa hơn nữa) phạm vi dựa trên vòng lặp for

std::vector<Foo> vFoo; 
// populate vFoo with some values... 
int totalSize = 0; 
for (const auto& element: vFoo) { 
    totalSize += element.size(); 
} 
Các vấn đề liên quan