Summation of the elements of the structure inside the vector

Consider the following:

typedef struct { int a; int b; int c; int d; } ABCD; typedef std::vector<ABCD> VecABCD; 

Let's say I wanted to add each element of 'a' to a vector of type VecABCD. Easily! I just loop through the vector and summarize when I go.

 int CalcSumOfA(const VecABCD &vec) { int sumOfA = 0; VecABCD::const_iterator it; for(it=vec.begin();it!=vec.end();it++) sumOfA += it->a; return sumOfA; } 

Say I wanted to do the same with "b"? Easily! I would write ... in fact, the same function, but only with minor changes. Same thing with 'c' and 'd'.

So, is there a more concise, less repetitive way to do this? I would like to do something like:

 int sumOfA = SumOfMembers(myVec, a); 

but I can’t imagine how I would connect such a function. Ideally, this would be a template, and I could use it with a vector of any structure not related to VecABCD. Does anyone have any idea?

+12
c ++ stl
Jun 23 '09 at 4:22
source share
5 answers

STL summation can be done using std::accumulate

 #include <functional> accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(&ABCD::a, _2))) 

If you want this to be more general, you can take the tr1 :: function for the member you want to bind:

 int sum_over_vec(const vector<ABCD>& v, const tr1::function<int (const ABCD&)>& member) { return accumulate(v.begin(), v.end(), 0, bind(plus<int>(), _1, bind(member, _2))); }; // ... int sum_a = sum_over_vec(vec, bind(&ABCD::a, _1)); 



Another way to do this, instead of putting your logic in a functor, is to put the logic in an iterator using the boost :: transform iterator:

 tr1::function<int (const ABCD&)> member(bind(&ABCD::a, _1)); accumulate(make_transform_iterator(v.begin(), member), make_transform_iterator(v.end(), member), 0); 

EDITED TO ADD: C ++ 11 lambda syntax

This becomes somewhat clearer with lambdas C ++ 11 (although, unfortunately, no shorter):

 accumulate(v.begin(), v.end(), 0, [](int sum, const ABCD& curr) { return sum + curr.a }); 

and

 int sum_over_vec(const vector<ABCD>& v, const std::function<int (const ABCD&)>& member) { return accumulate(v.begin(), v.end(), 0, [&](int sum, const ABCD& curr) { return sum + member(curr}); }); }; 

Using:

 // Use a conversion from member function ptr to std::function. int sum_a = sum_over_vec(vec, &ABCD::a); // Or using a custom lambda sum the squares. int sum_a_squared = sum_over_vec(vec, [](const ABCD& curr) { return curr.a * curr.a; }); 
+14
Jun 23 '09 at 4:32
source share

Another option is to use member-pointer:

 int CalcSumOf(const VecABCD & vec, int ABCD::*member) { int sum = 0; for(VecABCD::const_iterator it = vec.begin(), end = vec.end(); it != end; ++it) sum += (*it).*member; return sum; } ... int sumA = CalcSumOf(myVec, &ABCD::a); // find sum of .a members int sumB = CalcSumOf(myVec, &ABCD::b); // find sum of .b members // etc. 
+9
Jun 23 '09 at 5:05
source share

You can use for_each . Its an option.

 #include <iostream> #include <algorithm> #include <vector> using namespace std; typedef struct{ int a; }ABCD; typedef vector<ABCD> vecABCD; struct sum : public unary_function<ABCD, void> { sum(){count.a=count.b=count.c=count.d=0;} void operator() (ABCD x) { count.a+=xa; count.b+=xb; count.c+=xc; count.d+=xd; } ABCD count; }; int main() { ABCD s1={1,2,3,4}; ABCD s2={5,6,7,8}; vecABCD v; v.push_back(s1); v.push_back(s2); sum s = for_each(v.begin(), v.end(), sum()); cout<<s.count.a<<endl; } 

exit:

 4 
+1
Jun 23 '09 at 4:30
source share
+1
Jun 23 '09 at 4:31
source share

Add another option, unfortunately ugly. You can take the relative address from the beginning of the ABCD structure to the member using the offsetof function. Put the return value in the function, and it can do the calculation using the relative location from the beginning of each structure. If your types may differ from int, you can also provide size information.

0
Jun 23 '09 at 4:35
source share



All Articles