views:

737

answers:

6

Hi,

As the function accepted by for_each take only one parameter (the element of the vector), I have to define a static int sum = 0 somewhere so that It can be accessed after calling the for_each . I think this is awkward. Any better way to do this (still use for_each) ?

#include <algorithm>
#include <vector>
#include <iostream>

using namespace std;

static int sum = 0;
void add_f(int i )
{
    sum += i * i;

}
void test_using_for_each()
{
    int arr[] = {1,2,3,4};
    vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    for_each( a.begin(),a.end(), add_f);
    cout << "sum of the square of the element is  " << sum << endl;
}

In Ruby, We can do it this way:

sum = 0
[1,2,3,4].each { |i| sum += i*i}   #local variable can be used in the callback function
puts sum    #=> 30

Would you please show more examples how for_each is typically used in practical programming (not just print out each element)? Is it possible use for_each simulate 'programming pattern' like map and inject in Ruby (or map /fold in Haskell).

#map in ruby 
>> [1,2,3,4].map  {|i| i*i} 
=> [1, 4, 9, 16]

#inject in ruby 
[1, 4, 9, 16].inject(0)  {|aac ,i| aac +=i}  #=> 30

EDIT: Thank you all. I have learned so much from your replies. We have so many ways to do the same single thing in C++ , which makes it a little bit difficult to learn. But it's interesting :)

+13  A: 

Use std::accumulate

#include <vector>
#include <numeric>

// functor for getting sum of previous result and square of current element
template<typename T>
struct square
{
    T operator()(const T& Left, const T& Right) const
    { 
     return (Left + Right*Right);
    }
};

void main()
{
    std::vector <int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);

    int x = std::accumulate( v1.begin(), v1.end(), 0, square<int>() );
    // 0 stands here for initial value to which each element is in turn combined with
    // for our case must be 0.
}

You could emulate std::accumulate as in nice GMan's answer, but I believe that using std::accumulate will make your code more readable, because it was designed for such purposes. You could find more standard algorithms here.

Kirill V. Lyadvinsky
I don't think vector iterators are guaranteed to be in the std namespace. If that's correct then ADL is not guaranteed to work here, and the questioner has not specified a compiler.
Steve Jessop
You're right. I've just checked - standard doesn't guarantee that iterator is a part of std namespace. Only reverse iterators are part of `std` namespace.
Kirill V. Lyadvinsky
onebyone: Wow, good catch. I checked the standard and you're absolutely right. So e.g. if vector<T>::iterator was typedefed to T*, ADL would indeed fail. -1ing to get the OP's attention... (The post is otherwise excellent BTW.)
j_random_hacker
OK that was fast, no need to -1 after all! :)
j_random_hacker
+7  A: 

for_each returns (a copy of) the functor that it was using. So, something like this:

#include <algorithm>
#include <vector>
#include <iostream>

template <typename T>
class square_accumulate
{
public:
    square_accumulate(void) :
      _sum(0)
      {
      }

      const T& result(void) const
      {
       return _sum;
      }

      void operator()(const T& val)
      {
       _sum += val * val;
      }

private:
    T _sum;
};

int main(void)
{
    int arr[] = {1,2,3,4};
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    int sum = std::for_each(a.begin(), a.end(), square_accumulate<int>()).result();

    std::cout << "sum of the square of the element is " << sum << std::endl;
}

As demonstrated by other answers, though, std::accumulate is the best way to go.

GMan
+1, I didn't think of that.
j_random_hacker
This is a good sample of std::accumulate emulation. Useful for teaching purposes.
Kirill V. Lyadvinsky
Down vote comment? Can't improve if I don't know what's wrong.
GMan
+3  A: 

As a general solution to such issue with STL: instead of passing a function, you can pass a functor -- for example, an instance of any class implementing operator(). This is much better than relying on global variables, since said instance can keep and update its own state! You could think of it as a kind of "compile time duck typing": generic programming does not constrain you to pass a "function" in that place, anything that "behaves like a function" (i.e., has a proper operator()) will do as well!-)

Alex Martelli
+3  A: 

Don't use for_each() for this, use accumulate() from the <numeric> header:

#include <numeric>
#include <iostream>
using namespace std;

struct accum_sum_of_squares {
    // x contains the sum-of-squares so far, y is the next value.
    int operator()(int x, int y) const {
     return x + y * y;
    }
};

int main(int argc, char **argv) {
    int a[] = { 4, 5, 6, 7 };

    int ssq = accumulate(a, a + sizeof a / sizeof a[0], 0, accum_sum_of_squares());
    cout << ssq << endl;
    return 0;
}

The default behaviour of accumulate() is to sum elements, but you can provide your own function or functor as we do here, and the operation it performs need not be associative -- the 2nd argument is always the next element to be operated on. This operation is sometimes called reduce in other languages.

You could use a plain function instead of the accum_sum_of_squares functor, or for even more genericity, you could make accum_sum_of_squares a class template that accepts any numeric type.

j_random_hacker
+9  A: 

No, don't use std::accumulate() use std::inner_product(). No functor required.

#include <vector>
#include <numeric>

void main()
{
    std::vector <int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);

    int x = std::inner_product( v1.begin(), v1.end(), v1.begin(), 0 );
}
mocj
Cute!
j_random_hacker
Very elegant...exactly what I was looking for!
Jacob
Why this isn't the top answer?
brubelsabs
+2  A: 

std::for_each is for doing something with each element. If you want get a result from a calculation on all the elements, there's std::accumulate. If you are wanting Haskell's map behaviour, use std::transform.

You can abuse either of these three to do the same thing as any of the others, since ultimately they are just iterating over an iterator (except for transform's form that takes two iterators as input.) The point is that for_each is not a replacement for map/fold - that should be done by transform/accumulate - although C++ doesn't natively have something that expresses the map/fold concept as well as Haskell does - but both gcc and VC++ support OpenMP which has a much better analogue in #pragma omp parallel for.

Inject in Ruby is a much closer match to calling for_each with a full-fledged functor, like GMan explained above. Lambda functions with variable capture in C++0X will make the behaviour between the two languages even more similar:

int main(void)
{
    int arr[] = {1,2,3,4};
    std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));

    int sum = 0;
    std::for_each(a.begin(), a.end(), [&](int i) { sum += i*i;} );

    std::cout << "sum of the square of the element is " << sum << std::endl;
}
Eclipse
should be sum += i*i;
mskfisher