Skip to content

Latest commit

 

History

History
1186 lines (706 loc) · 41.9 KB

CppExerciseNoForLoops.md

File metadata and controls

1186 lines (706 loc) · 41.9 KB

 

 

 

 

 

 

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 [1][2]

 

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++11 standard.

 

 

 

 

 

Table of contents

 

 

 

 

 

 

Question #0: Triple

 

Replace the for-loop. You will need:

 


#include <vector>   void Triple(std::vector<int>& v) {   const int sz = v.size();   for (int i=0; i!=sz; ++i)   {     v[i]*=3;   } }

 

 

 

 

 

 

Question #1: AddTwo

 

Replace the for-loop. You will need:

 


#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; }

 

 

 

 

 

 

Question #2: Multiply

 

Replace the for-loop. You will need:

 


#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;   } }

 

 

 

 

 

 

Question #3: Add

 

Replace the for-loop. You will need:

 


#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; }

 

 

 

 

 

 

Question #4: Widget::DoIt on Widget

 

Replace the for-loop. You will need:

 


#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();   } }

 

 

 

 

 

 

Question #5: Widget::DoItOften on Widget

 

Replace the for-loop. You will need:

 


#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);   } }

 

 

 

 

 

 

Question #6: Widget::DoIt on Widget*

 

Replace the for-loop. You will need:

 


#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();   } }

 

 

 

 

 

 

Question #7: Widget::DoItOften on Widget*

 

Replace the for-loop. You will need:

 


#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);   } }

 

 

 

 

 

 

Question #8: GetSum

 

Replace the for-loop. You will need:

 


#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; }

 

 

 

 

 

 

Question #9: Product

 

Replace the for-loop. You will need:

 


#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; }

 

 

 

 

 

 

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

 

Replace the for-loop. You will need:

 


#include <vector> #include <boost/shared_ptr.hpp>   struct Widget {   void DoIt() const { /* do it */ } };   void DoIt(const std::vector<boost::shared_ptr<Widget> >& v) {   const std::size_t sz = v.size();   for (std::size_t i=0; i!=sz; ++i)   {     v[i]->DoIt();   } }

 

 

 

 

 

 

Question #11: ReplaceZeroByOne

 

Replace the for-loop. You will need:

 


#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;   } }

 

 

 

 

 

 

Question #12: ReplaceNegativeByZero

 

Replace the for-loop. You will need:

 


#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;   } }

 

 

 

 

 

 

Question #13: MakeAbs

 

Replace the for-loop. You will need:

 


#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]);   } }

 

 

 

 

 

 

Question #14: MakeSquare

 

Replace the for-loop. You will need:

 


#include <vector>   void MakeSquare(std::vector<int>& v) {   const int sz = v.size();   for (int i=0; i!=sz; ++i)   {     v[i]*=v[i];   } }

 

 

 

 

 

 

Question #15: CoutVector

 

Replace the for-loop. You will need:

 


#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';   } }

 

 

 

 

 

 

Question #16: Reciprocal

 

Replace the for-loop. You will need:

 


#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];   } }

 

 

 

 

 

 

Question #17: Halve

 

Replace the for-loop. You will need:

 


#include <vector>   void Halve(std::vector<double>& v) {   const int sz = v.size();   for (int i=0; i!=sz; ++i)   {     v[i]/=2.0;   } }

 

 

 

 

 

 

Question #18: SumPositives

 

Replace the for-loop. You will need:

 


int SumPositives(const std::vector<int>& v) {   const size_t sz = v.size();   int sum = 0;   for (size_t i=0; i!=sz; ++i)   {     if (v[i]>0) sum+=v[i];   }   return sum; }

 

 

 

 

 

 

 

Replace the for-loop. You will need:

 


int ProductNonZeroPositives(const std::vector<int>& v) {   const size_t sz = v.size();   int product = 0;   for (size_t i=0; i!=sz; ++i)   {     if (v[i]>0) product*=v[i];   }   return product; }

 

 

 

 

 

 

Question #20: CountNonZeroPositives

 

Replace the for-loop. You will need:

 


#include <vector> int CountNonZeroPositives(const std::vector<int>& v) {   int sum = 0;   const size_t sz = v.size();   for (size_t i = 0; i!=sz; ++i)   {     if (v[i]>0) sum+=v[i];   } }

 

 

 

 

 

 

Question #21: CopyFirst

 

Replace the for-loop. You will need:

 


#include <vector> ///CopyFirst copies the first std::pair elements from a std::vector of std::pairs //From http://www.richelbilderbeek.nl/CppCopyFirst.htm template <class T, class U> const std::vector<T> CopyFirst(const std::vector<std::pair<T,U> >& v) {   std::vector<T> w;   const int size = static_cast<int>(v.size());   for (int i=0; i!=size; ++i)   {     w.push_back(v[i].first);   }   return w; }

 

 

 

 

 

 

Question #22: CopySecond

 

Replace the for-loop. You will need:

 


#include <vector> ///CopySecond copies the second std::pair elements from a std::vector of std::pairs //From http://www.richelbilderbeek.nl/CppCopySecond.htm template <class T, class U> const std::vector<U> CopySecond(const std::vector<std::pair<T,U> >& v) {   std::vector<U> w;   const int size = static_cast<int>(v.size());   for (int i=0; i!=size; ++i)   {     w.push_back(v[i].second);   }   return w; }

 

 

 

 

 

 

Question #23: SumFirst

 

Replace the for-loop. You will need:

 


int SumFirst(const std::vector<std::pair<int,int> >& v) {   const int size = static_cast<int>(v.size());   int sum = 0;   for (int i=0; i!=size; ++i)   {     sum+=v[i].first;   }   return sum; }

 

 

 

 

 

 

Question #24: SumSecond

 

Replace the for-loop. You will need:

 


int SumSecond(const std::vector<std::pair<int,int> >& v) {   const int size = static_cast<int>(v.size());   int sum = 0;   for (int i=0; i!=size; ++i)   {     sum+=v[i].second;   }   return sum; }

 

 

 

 

 

 

Question #25: HasMale on std::vector<Person*>

 

Replace the for-loop. You will need:

 


#include <vector> #include <boost/numeric/conversion/cast.hpp> struct Person {   Person(const bool is_male) : m_is_male(is_male) {}   bool IsMale() const { return m_is_male; }   const bool m_is_male; }; bool HasMale(const std::vector<const Person *>& v) {   const int size = boost::numeric_cast<int>(v.size());   for (int i=0; i!=size; ++i)   {     if (v[i]->IsMale()) return true;   }   return false; }

 

 

 

 

 

 

Question #26: HasFemale on std::vector<Person*>

 

Replace the for-loop. You will need:

 


#include <vector> #include <boost/numeric/conversion/cast.hpp> struct Person {   Person(const bool is_male) : m_is_male(is_male) {}   bool IsMale() const { return m_is_male; }   const bool m_is_male; }; bool HasFemale(const std::vector<const Person *>& v) {   const int size = boost::numeric_cast<int>(v.size());   for (int i=0; i!=size; ++i)   {     if (!v[i]->IsMale()) return true;   }   return false; }

 

 

 

 

 

 

Question #27: HasId on std::vector<Person*>

 

Replace the for-loop. You will need:

 


#include <vector> #include <boost/numeric/conversion/cast.hpp> struct Person {   Person(const int id) : m_id(id) {}   int GetId() const { return m_id; }   const int m_id; }; bool HasId(const std::vector<const Person *>& v, const int id) {   const int size = boost::numeric_cast<int>(v.size());   for (int i=0; i!=size; ++i)   {     if (v[i]->GetId() == id) return true;   }   return false; }

 

 

 

 

 

 

Question #28: GetMaxId on std::vector<Person*>

 

Replace the for-loop. You will need:

 


#include <cassert> #include <vector> #include <boost/numeric/conversion/cast.hpp> struct Person {   Person(const int id) : m_id(id) {}   int GetId() const { return m_id; }   const int m_id; }; const Person * GetMaxId(const std::vector<const Person *>& v) {   assert(!v.empty());   const int size = boost::numeric_cast<int>(v.size());   int max_id = v[0]->GetId();   int index_max_id = 0;   for (int i=1; i!=size; ++i)   {     const int id = v[i]->GetId();     if (id > max_id)     {       max_id = id;       index_max_id = i;     }   }   return v[index_max_id]; }

 

 

 

 

 

 

Question #29: GetAllTrue on std::map<int,bool>

 

Replace the BOOST_FOREACH. You will need:

 


#include <cassert> #include <map> #include <boost/foreach.hpp> ///Returns true if all bools are true bool GetAllTrue(const std::map<int,bool>& v) {   assert(!v.empty());   typedef std::pair<int,bool> Pair;   BOOST_FOREACH(const Pair& p,v)   {     if (p.second == false) return false;   }   return true; }

 

 

 

 

 

 

Question #30: Get maximum value from std::map<const Person *,int>

 

Replace the for-loop. You will need:

 


#include <cassert> #include <limits> #include <map> #include <boost/foreach.hpp> struct Person { }; const Person * GetPersonWithMaxIdStl(const std::map<const Person *,int>& v) {   assert(!v.empty());   int max_id =  std::numeric_limits<int>::min();   const Person * ptr = 0;   typedef std::pair<const Person *,int> Pair;   BOOST_FOREACH(const Pair& p,v)   {     if (p.second > max_id)     {       max_id = p.second;       ptr = p.first;     }   }   assert(ptr);   return ptr; }

 

 

 

 

 

 

Question #31: Find an ID in a std::vector<const Person*>

 

Replace the for-loop. You will need:

 


#include <algorithm> #include <vector> struct Id {   Id(const int id) : m_id(id) { }   int Get() const { return m_id; }   private:   int m_id; }; struct Person {   Person(const int id) : m_id(new Id(id)) {}   const Id * GetId() const { return m_id.get(); }   private:   boost::scoped_ptr<Id> m_id; }; bool IsIdTaken(const std::vector<const Person*>& v, const int id) {   const int sz = static_cast<int>(v.size());   for (int i=0; i!=sz; ++i)   {     if (v[i]->GetId()->Get() == id) return true;   }   return false; }

 

 

 

 

 

 

Question #32: Sum all persons' money from a std::vector<const Person*>

 

Replace the for-loop. You will need:

 


#include <vector> struct Person {   Person(const int money) : m_money(money) {}   int GetMoney() const { return m_money; }   private:   int m_money; }; int SumMoney(const std::vector<const Person*>& v) {   int sum = 0;   const int sz = v.size();   for (int i=0; i!=sz; ++i)   {     sum+=v[i]->GetMoney();   }   return sum; }

 

 

 

 

 

 

Post your feedback

 

 

 

 

 

 

  1. Bjarne Stroustrup. The C++ Programming Language (3rd edition). ISBN: 0-201-88954-4. Chapter 18.12.1 : 'Prefer algorithms over loops'
  2. 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.'