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:
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.
- Question #0: Triple
- Question #1: AddTwo
- Question #2: Multiply
- Question #3: Add
- Question #4: Widget::DoIt on Widget
- Question #5: Widget::DoItOften on Widget
- Question #6: Widget::DoIt on Widget*
- Question #7: Widget::DoItOften on Widget*
- Question #8: GetSum
- Question #9: Product
- Question #10: Widget::DoIt on boost::shared_ptr<Widget>
- Question #11: ReplaceZeroByOne
- Question #12: ReplaceNegativeByZero
- Question #13: MakeAbs
- Question #14: MakeSquare
- Question #15: CoutVector
- Question #16: Reciprocal
- Question #17: Halve
- Question #18: SumPositives
- Question #19: ProductNonZeroPositives
- Question #20: CountNonZeroPositives
- Question #21: CopyFirst
- Question #22: CopySecond
- Question #23: SumFirst
- Question #24: SumSecond
- Question #25: HasMale on std::vector<Person*>
- Question #26: HasFemale on std::vector<Person*>
- Question #27: HasId on std::vector<Person*>
- Question #28: GetMaxId on std::vector<Person*>
- Question #29: GetAllTrue on std::map<int,bool>
- Question #30: Get maximum value from std::map<const Person *,int>
- Question #31: Find an ID in a std::vector<const Person*>
- Question #32: Sum all persons' money from a std::vector<const Person*>
- See also: Get the length of the longest string
- Post your feedback
- References
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; }
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(); } }
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); } }
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(); } }
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; }
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:
- 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; } }
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:
- 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]); } }
Question #14: MakeSquare
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]; } }
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:
- std::greater
- A conditional std::accumulate
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; }
Question #19: ProductNonZeroPositives
Replace the for-loop. You will need:
- std::bind2nd
- std::greater
- std::multiplies
- A conditional std::accumulate
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; }
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; }
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; }
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; }
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]; }
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; }
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; }
- Bjarne Stroustrup. The C++ Programming Language (3rd edition). ISBN: 0-201-88954-4. Chapter 18.12.1 : 'Prefer algorithms over loops'
- 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.'