Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

(C++) Exercise #9: No for-loops

 

Difficulty: 5/10

Date added: 29th of December 2009

 

In this exercise, you learn to replace for-loops by algorithms.

 

Reading the literature, one reads:

 

 

Prefer algorithms over loops [0][1].

 

 

This is easier said than done.

 

In this exercise you must replace for-loops by using a combination of all those algorithm things like std::for_each, std::transform, std::bind1st, std::bind2nd, std::multiplies and more of the likes. It is up to you to find the correct combination.

 

The exercises are unordered. Some require Boost, but will be in namespace std after the C++0x standard.

 

Table of contents

(C++) Exercise #9: No for-loops 1

Table of contents 1

Question #0: Triple 2

Question #1: AddTwo 2

Question #2: Multiply 3

Question #3: Add 3

Question #4: Widget::DoIt on Widget 4

Question #5: Widget::DoItOften on Widget 4

Question #6: Widget::DoIt on Widget* 5

Question #7: Widget::DoItOften on Widget* 5

Question #8: Sum a std::vector<int> 6

Question #9: Product of std::vector<int> 6

Question #10: Widget::DoIt on boost::shared_ptr<Widget> 7

Question #11: Replace zero by one 7

Question #12: Replace negative by zero 8

Question #13: Make absolute 8

Question #14: Make square 9

Question #15: write to std::cout 9

Question #16: Reciprocal 10

Question #17: Halve 10

Post your feedback 11

References 11

 

 

 

 

 

Question #0: Triple

 

Replace the for-loop. You will need:

*       std::bind2nd

*       std::for_each

*       std::multiplies

 

 

#include <vector>

 

void Triple(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]*=3;

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #1: AddTwo

 

Replace the for-loop. You will need:

*       std::back_inserter

*       std::bind2nd

*       std::plus

*       std::transform

 

 

#include <vector>

 

const std::vector<int> AddTwo(const std::vector<int>& v)

{

  std::vector<int> v_new(v); //Copy original vector

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v_new[i]+=2;

  }

  return v_new;

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #2: Multiply

 

Replace the for-loop. You will need:

*       std::bind2nd

*       std::multiplies

*       std::transform

 

 

#include <vector>

 

void Multiply(std::vector<int>& v, const int x)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]*=x;

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #3: Add

 

Replace the for-loop. You will need:

*       std::back_inserter

*       std::bind2nd

*       std::plus

*       std::transform

 

 

#include <vector>

 

const std::vector<int> Add(const std::vector<int>& v, const int x)

{

  std::vector<int> v_new(v); //Copy original vector

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v_new[i]+=x;

  }

  return v_new;

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #4: Widget::DoIt on Widget

 

Replace the for-loop. You will need:

*       std::for_each

*       std::mem_fun_ref (or boost::mem_fn)

 

 

#include <vector>

 

struct Widget

{

  void DoIt() const { /* do it */ }

};

 

void DoIt(const std::vector<Widget>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i].DoIt();

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #5: Widget::DoItOften on Widget

 

Replace the for-loop. You will need:

*       std::bind2nd (or boost::bind)

*       std::for_each

*       std::mem_fun_ref (or boost::mem_fn)

 

 

 

#include <vector>

 

struct Widget

{

  void DoItOften(const int n) const { /* do it n times */ }

};

 

void DoItOften(const std::vector<Widget>& v, const int n)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i].DoItOften(n);

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #6: Widget::DoIt on Widget*

 

Replace the for-loop. You will need:

*       std::for_each

*       std::mem_fun (or boost::mem_fn)

 

 

 

#include <vector>

 

struct Widget

{

  void DoIt() const { /* do it */ }

};

 

void DoIt(const std::vector<Widget*>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]->DoIt();

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #7: Widget::DoItOften on Widget*

 

Replace the for-loop. You will need:

*       std::bind2nd (or boost::bind)

*       std::for_each

*       std::mem_fun (or boost::mem_fn)

 

 

 

#include <vector>

 

struct Widget

{

  void DoItOften(const int n) const { /* do it n times */ }

};

 

void DoItOften(const std::vector<Widget*>& v, const int n)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]->DoItOften(n);

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #8: GetSum

 

Replace the for-loop. You will need:

*       std::accumulate

 

 

#include <vector>

 

const int GetSum(const std::vector<int>& v)

{

  const int sz = v.size();

  const int sum = 0;

  for (int i=0; i!=sz; ++i)

  {

    sum+=v[i];

  }

  return sum;

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #9: Product of std::vector<int>

 

Replace the for-loop. You will need:

*       std::accumulate

*       std::multiplies

 

 

 

#include <vector>

 

const int Product(const std::vector<int>& v)

{

  const int sz = v.size();

  const int product = 1;

  for (int i=0; i!=sz; ++i)

  {

    product*=v[i];

  }

  return product;

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #10: Widget::DoIt on boost::shared_ptr<Widget>

 

Replace the for-loop. You will need:

*       std::for_each

*       boost::mem_fn

 

 

 

#include <vector>

#include <boost/shared_ptr.hpp>

 

struct Widget

{

  void DoIt() const { /* do it */ }

};

 

void DoIt(const boost::shared_ptr<std::vector<Widget> >& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]->DoIt();

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #11: Replace zero by one

 

Replace the for-loop. You will need:

*       std::replace (or std::replace_if with std::bind2nd)

 

 

#include <vector>

 

void ReplaceZeroByOne(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    if(v[i]==0) v[i]=1;

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #12: Replace negative by zero

 

Replace the for-loop. You will need:

*       std::bind2nd

*       std::less

*       std::replace_if

 

 

#include <vector>

 

void ReplaceNegativeByZero(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    if(v[i]<0) v[i]=0;

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #13: Make absolute

 

Replace the for-loop. You will need:

*       std::transform

*       your own std::unary_function

 

 

#include <cmath>

#include <vector>

 

void MakeAbs(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i] = std::abs(v[i]);

  }

}

 

 

View the answer of this exercise

 

 

 

 

Question #14: Make square

 

Replace the for-loop. You will need:

*       std::transform

*       your own std::unary_function

 

 

#include <vector>

 

void MakeSquare(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]*=v[i];

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #15: write to std::cout

 

Replace the for-loop. You will need:

*       std::copy

*       std::ostream_iterator

 

 

#include <vector>

 

void CoutVector(std::vector<int>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    std::cout << v[i] << '\n'; 

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #16: Reciprocal

 

Replace the for-loop. You will need:

*       std::bind1st

*       std::divides

*       std::transform

 

 

#include <vector>

 

void Reciprocal(std::vector<double>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]=1.0/v[i];

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Question #17: Halve

 

Replace the for-loop. You will need:

*       std::bind2nd

*       std::divides

*       std::transform

 

 

#include <vector>

 

void Halve(std::vector<double>& v)

{

  const int sz = v.size();

  for (int i=0; i!=sz; ++i)

  {

    v[i]/=2.0;

  }

}

 

 

View the answer of this exercise

 

 

 

 

 

Post your feedback

 

Feel free to post your feedback about this exercise at Programmer's Heaven.

 

 

 

 

 

References

[0]         Bjarne Stroustrup. The C++ Programming Language (3rd edition). ISBN: 0-201-88954-4. Chapter 18.12.1 : 'Prefer algorithms over loops'

[1]         Herb Sutter and Andrei Alexandrescu. C++ coding standards: 101 rules, guidelines, and best practices. ISBN: 0-32-111358-6. Chapter 84: 'Prefer algorithm calls to handwritten loops.'

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.