behzad.nouri
behzad.nouri

Reputation: 77941

STL algorithms and iterators instead of "for" loops

I guess that there should be someway to write the below piece of code without using "for" loops and by just using STL algorithms and iterators. If I am not wrong can anyone guide me on how to do this?

std::vector<double> A(N);
std::vector<double> B(N);
std::vector<double> C(N);
std::vector<double> D(N);

for(int i = 0; i < N; ++i)
  A[i] = myFunction1(i);

for(int i = 0; i < N; ++i)
  B[i] = myFunction2(A[i], i);

for(int i = 0; i < N; ++i)
  C[i] = myFunction3(A[i], B[i]);

for(int i = 0; i < N; ++i)
  D[i] = myFunction4(A[i], B[i], i);

Upvotes: 4

Views: 888

Answers (4)

Steve Jessop
Steve Jessop

Reputation: 279245

typedef boost::counting_iterator<int> counter;

std::transform(counter(0), counter(N), A.begin(), myFunction1);
std::transform(A.begin(), A.end(), counter(0), B.begin(), myFunction2);
std::transform(A.begin(), A.end(), B.begin(), C.begin(), myFunction3);

Now write your own version of std::transform that takes a ternary function:

template <typename In1, typename In2, typename In3, typename Out, typename FUNC>
Out transform3(In1 first1, In1 last1, In2 first2, In3 first3, Out out, FUNC f) {
    while (first1 != last1) {
        *out++ = f(*first1++, *first2++, *first3++);
    }
    return out;
}

transform3(A.begin(), A.end(), B.begin(), counter(0), D.begin(), myFunction4);

I guess there might be something you can do with variadic templates in C++0x to get a transform_N, but if so I don't know what it is, I've never used them. Not sure if you can forward a variable number of arguments with modifications (in this case wrapping * ++ around each one, as it were).

Upvotes: 4

Ben Voigt
Ben Voigt

Reputation: 283634

Example using std::transform

#include <algorithm>
#include <vector>

double myFunction1(int) { return 0; }
double myFunction2(double, int) { return 1; }
double myFunction3(double, double) { return 2; }
double myFunction4(double, double, int) { return 3; }

struct int_sequence
{
    int_sequence(int i) : val(i) {}
    int_sequence operator++() { ++val; return *this; }
    int_sequence operator++(int) { return int_sequence(val++); }
    int operator*() const { return val; }
    bool operator!=(const int_sequence& other) const { return val != other.val; }
private:
    int val;
};

const size_t N = 100;

int main(void)
{
    std::vector<double> A(N);
    std::vector<double> B(N);
    std::vector<double> C(N);
    std::vector<double> D(N);

    //for(int i = 0; i < N; ++i)
    //    A[i] = myFunction1(i);
    std::transform(int_sequence(0), int_sequence(N), A.begin(), &myFunction1);

    //for(int i = 0; i < N; ++i)
    //  B[i] = myFunction2(A[i], i);
    std::transform(A.begin(), A.end(), int_sequence(0), B.begin(), &myFunction2);

    //for(int i = 0; i < N; ++i)
    //  C[i] = myFunction3(A[i], B[i]);
    std::transform(A.begin(), A.end(), B.begin(), C.begin(), &myFunction3);

    for(int i = 0; i < N; ++i)
      D[i] = myFunction4(A[i], B[i], i);
    // there is no std::transform for three-argument functions (yet)

    return 0;
}

Upvotes: -1

Eclipse
Eclipse

Reputation: 45493

You will need a bit of BOOST to do this all with functional work (or else make your own versions of boost::counting_iterator)

//for(int i = 0; i < N; ++i)
//  A[i] = myFunction1(i);

std::transform(
     boost::counting_iterator<int>(0), 
     boost::counting_iterator<int>(N), 
     A.begin(), 
     &myFunction1);

//for(int i = 0; i < N; ++i)
//  B[i] = myFunction2(A[i], i);

std::transform(
     A.begin(),
     A.end(),
     boost::counting_iterator<int>(0), 
     B.begin(),
     &myFunction2);


//for(int i = 0; i < N; ++i)
//  C[i] = myFunction3(A[i], B[i]);
std::transform(
     A.begin(),
     A.end(),
     B.begin(),
     C.begin(),
     &myFunction3);

// The STL doesn't have a version of transform that takes three inputs, but given a transform_3 that does:
//for(int i = 0; i < N; ++i)
//  D[i] = myFunction4(A[i], B[i], i);
transform_3(
     A.begin(),
     A.end(),
     B.begin(),
     boost::counting_iterator<int>(0),
     D.begin(),
     &myFunction4);

That transform_3 function might look something like this:

// Untested code
template <class input1, class input2, class input3, class output, class oper>
output transform_3 (input1 in1begin, input1 in1end, input2 in2, input3 in3, output out, oper op)
{
    while (in1begin != in1end)
        *(out++) = op(*(in1begin++), *(in2++), *(in3++));
    return out;
}

Upvotes: 3

Daniel A. White
Daniel A. White

Reputation: 190935

Why not combine the 4 loops into 1?

for(int i = 0; i < N; ++i) {
  A[i] = myFunction1(i);
  B[i] = myFunction2(A[i], i);
  C[i] = myFunction3(A[i], B[i]);
  D[i] = myFunction4(A[i], B[i], i);
}

Upvotes: 1

Related Questions