What's a good implementation of applying a unary function to some elements of a vector?

I would like to apply a function UnaryFunction f

to some elements of the std container, given a predicate UnaryPredicate p

- the kind of what you would get if you concatenated std::partition

and then apply std::for_each

to one of the sections.

I'm new to C ++ so forgive my ignorance. However, I have searched for a suitable implementation in <algorithm>

but I cannot find the function I need.

Based on the possible implementations above cppreference.com I ended up with this:

template<class InputIt, class UnaryPredicate, class UnaryFunction>
UnaryFunction for_each_if(InputIt first, InputIt last, UnaryPredicate p, UnaryFunction f)
{
    for (; first != last; ++first) {
        if (p(*first))
        {
            f(*first);    
        }        
    }
    return f;
}

      

The return value is modeled as std::for_each

though OutputIter

it might have been a better choice. This would require a more confusing implementation, and so I chose brevity this time. The alternative implementation is left as an exercise for the reader.

My question is, is there an already installed way to do this in the std library? If not, would that be a reasonable implementation of such a function pattern?

+3


source to share


2 answers


The STL does not support composition of algorithms very well. As you said, you can call first partition

and then call for_each

on one of the sections if you don't need the order of the elements.

For a new project or one where you can submit libraries, I highly recommend taking a look at the range library, for example. Boost.Range or Eric Niebler range-v3 .



In the range library, this can be done like this:

template<typename R, typename P, typename F> 
F for_each_if(R& rng, P pred, F f)
{ 
    using namespace boost::adaptors;

    return (rng | filtered(pred) | for_each(f));
}

      

+4


source


As far as the comments are concerned, there seems to be no implementation in this library. However, as user 2672165 points out, a predicate can easily be included in a function. To illustrate this, see the following modified version of the example for_each

at cppreference.com
:

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

struct Sum {
    Sum() { sum = 0; }
    void operator()(int n) { sum += n; }

    int sum;
};

int main()
{
    std::vector<int> nums{3, 4, 2, 9, 15, 267};

    std::cout << "before: ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << '\n';

    std::for_each(nums.begin(), nums.end(), [](int &n){ if (n > 5) n++; });

    // Calls Sum::operator() for each number
    Sum s = std::for_each(nums.begin(), nums.end(), Sum());

    std::cout << "after:  ";
    for (auto n : nums) {
        std::cout << n << " ";
    }
    std::cout << '\n';
    std::cout << "sum: " << s.sum << '\n';
}

      

Here the predicate is added to the function, so it [](int &n){ n++; }

now becomes [](int &n){ if (n > 5) n++; }

to apply this function only to integer elements greater than 5.



Expected Result

before: 3 4 2 9 15 267 
after:  3 4 2 10 16 268 
sum: 303

      

Hope this helps someone else.

+1


source







All Articles