Binary predicate for `std::count_if` is not working - c++

I am currently trying to use a lambda function to std::count_if the sum of two consecutive elements in an array equal to a number. A sample code is given below.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
const int Number = 3;
std::vector<int> vec = {1,1,2,4,5,6};
auto count = std::count_if( vec.begin(), vec.end(),
[&](int A, int B) -> bool
{ return A+B == Number; });
std::cout << count << '\n';
}
The output should be 1, since we have one possible case( 1 + 2 ).
However, I could not succeed. Can anybody tell me what do I miss?
Here is the error msg:
|234|error: no match for call to '(main()::<lambda(int, int)>) (int&)'|

Problem is that std::count_if uses unary predicate. What compiler tells you: "You gave me a lambda with 2 arguments, I expected lambda with one argument".
I believe what you are looking for is std::adjacent_find. It compares every two adjacent elements of a container (possibly using a binary predicate).

Another possible option is to use std::inner_product. First I'd write a little helper function:
#include <numeric>
#include <functional>
#include <iterator>
template <typename ForwardIterator, typename BinaryPredicate>
auto count_pairs_if(ForwardIterator first, ForwardIterator last,
BinaryPredicate pred)
{
const auto n = std::distance(first, last);
if (n < 2) return std::size_t {0};
return std::inner_product(first, std::next(first, n - 1), std::next(first),
std::size_t {0}, std::plus<> {}, pred);
}
template <typename Range, typename BinaryPredicate>
auto count_pairs_if(const Range& values, BinaryPredicate pred)
{
return count_pairs_if(std::cbegin(values), std::cend(values), pred);
}
Then you can use it like:
auto count = count_pairs_if(vec, [=] (auto lhs, auto rhs) { return lhs + rhs == Number; });
Here's a demo.

As #Yksisarvinen explained, the std::count_if is designed for the unary predicate. Therefore the compiler can not accept the lambda, I passed.
After a while, I have found another solution to this problem. If I provide a templated function, which takes
iterators(i.e. start and end) of the container (on which I need to do the adjacent element check), and
the binary predicate, which will be used for checking adjacent relationship
that could be a more natural solution, like any other standard algorithm. (See a live demo online)
template <typename Iterator, typename BinaryPred = std::equal_to<>>
constexpr std::size_t count_adjacent_if(
Iterator beginIter,
const Iterator endIter,
const BinaryPred pred = {})
{
if (beginIter == endIter) return 0; // nothing to do!
std::size_t count{};
for (Iterator nextIter{ beginIter }; ++nextIter != endIter; beginIter = nextIter)
if (pred(*beginIter, *nextIter))
++count;
return count;
}
and can be called like:
const auto count = ::count_adjacent_if(
vec.cbegin(), vec.cend(), [number](const int lhs, const int rhs) { return lhs + rhs == number; }
);
Or like #bipil mentioned in the comments, let the predicate remember the previous element. Which is less recommended, since it is a non-generic solution and needs the non-empty container. (See a live demo online)
int lhs = vec[0];
const auto count = std::count_if(vec.cbegin() + 1, vec.cend(),
[&](const int rhs) {
const bool condition = (lhs + rhs == number); // check for the condition
lhs = rhs; // change the lhs = rhs (i.e. current element = next element)
return condition; // return the condition
});

Related

What STL algorithm can determine if exactly one item in a container satisfies a predicate?

I need an STL algorithm that takes a predicate and a collection and returns true if one and only one member of the collection satisfies the predicate, otherwise returns false.
How would I do this using STL algorithms?
E.g., to replace the following with STL algorithm code to express the same return value.
int count = 0;
for( auto itr = c.begin(); itr != c.end(); ++itr ) {
if ( predicate( *itr ) ) {
if ( ++count > 1 ) {
break;
}
}
}
return 1 == count;
Two things come to my mind:
std::count_if and then compare the result to 1.
To avoid traversing the whole container in case eg the first two elements already match the predicate I would use two calls looking for matching elements. Something along the line of
auto it = std::find_if(begin,end,predicate);
if (it == end) return false;
++it;
return std::none_of(it,end,predicate);
Or if you prefer it more compact:
auto it = std::find_if(begin,end,predicate);
return (it != end) && std::none_of(std::next(it),end,predicate);
Credits goes to Remy Lebeau for compacting, Deduplicator for debracketing and Blastfurnance for realizing that we can also use none_of the std algorithms.
You can use std::count_if† to count and return if it is one.
For example:
#include <iostream>
#include <algorithm> // std::count_if
#include <vector> // std::vector
#include <ios> // std::boolalpha
template<class Iterator, class UnaryPredicate>
constexpr bool is_count_one(Iterator begin, const Iterator end, UnaryPredicate pred)
{
return std::count_if(begin, end, pred) == 1;
}
int main()
{
std::vector<int> vec{ 2, 4, 3 };
// true: if only one Odd element present in the container
std::cout << std::boolalpha
<< is_count_one(vec.cbegin(), vec.cend(),
[](const int ele) constexpr noexcept -> bool { return ele & 1; });
return 0;
}
†Update: However, std::count_if counts entire element in the container, which is not good as the algorithm given in the question. The best approach using the standard algorithm collections has been mentioned in #formerlyknownas_463035818 's answer.
That being said, OP's approach is also good as the above mentioned best standard approach, where a short-circuiting happens when count reaches 2. If someone is interested in a non-standard algorithm template function for OP's approach, here is it.
#include <iostream>
#include <vector> // std::vector
#include <ios> // std::boolalpha
#include <iterator> // std::iterator_traits
template<class Iterator, class UnaryPredicate>
bool is_count_one(Iterator begin, const Iterator end, UnaryPredicate pred)
{
typename std::iterator_traits<Iterator>::difference_type count{ 0 };
for (; begin != end; ++begin) {
if (pred(*begin) && ++count > 1) return false;
}
return count == 1;
}
int main()
{
std::vector<int> vec{ 2, 3, 4, 2 };
// true: if only one Odd element present in the container
std::cout << std::boolalpha
<< is_count_one(vec.cbegin(), vec.cend(),
[](const int ele) constexpr noexcept -> bool { return ele & 1; });
return 0;
}
Now that can be generalized, by providing one more parameter, the number of N element(s) has/ have to be found in the container.
template<typename Iterator>
using diff_type = typename std::iterator_traits<Iterator>::difference_type;
template<class Iterator, class UnaryPredicate>
bool has_exactly_n(Iterator begin, const Iterator end, UnaryPredicate pred, diff_type<Iterator> N = 1)
{
diff_type<Iterator> count{ 0 };
for (; begin != end; ++begin) {
if (pred(*begin) && ++count > N) return false;
}
return count == N;
}
Starting from formerlyknownas_463035818's answer, this can be generalized to seeing if a container has exactly n items that satisfy a predicate. Why? Because this is C++ and we're not satisfied until we can read email at compile time.
template<typename Iterator, typename Predicate>
bool has_exactly_n(Iterator begin, Iterator end, size_t count, Predicate predicate)
{
if(count == 0)
{
return std::none_of(begin, end, predicate);
}
else
{
auto iter = std::find_if(begin, end, predicate);
return (iter != end) && has_exactly_n(std::next(iter), end, count - 1, predicate);
}
}
Using std::not_fn to negate a predicate
As the core of the algorithm of this question (as has been elegantly covered by combining std::find_if and std::none_of in the accepted answer), with short-circuiting upon failure, is to scan a container for a unary predicate and, when met, continue scanning the rest of the container for the negation of the predicate, I will mention also the negator std::not_fn introduced in C++17, replacing the less useful std::not1 and std::not2 constructs.
We may use std::not_fn to implement the same predicate logic as the accepted answer (std::find_if conditionally followed by std::none_of), but with somewhat different semantics, replacing the latter step (std::none_of) with std::all_of over the negation of the unary predicate used in the first step (std::find_if). E.g.:
// C++17
#include <algorithm> // std::find_if
#include <functional> // std::not_fn
#include <ios> // std::boolalpha
#include <iostream>
#include <iterator> // std::next
#include <vector>
template <class InputIt, class UnaryPredicate>
constexpr bool one_of(InputIt first, InputIt last, UnaryPredicate p) {
auto it = std::find_if(first, last, p);
return (it != last) && std::all_of(std::next(it), last, std::not_fn(p));
}
int main() {
const std::vector<int> v{1, 3, 5, 6, 7};
std::cout << std::boolalpha << "Exactly one even number : "
<< one_of(v.begin(), v.end(), [](const int n) {
return n % 2 == 0;
}); // Exactly one even number : true
}
A parameter pack approach for static size containers
As I’ve already limited this answer to C++14 (and beyond), I’ll include an alternative approach for static size containers (here applied for std::array, specifically), making use of std::index_sequence combined with parameter pack expansion:
#include <array>
#include <ios> // std::boolalpha
#include <iostream>
#include <utility> // std::(make_)index_sequence
namespace detail {
template <typename Array, typename UnaryPredicate, std::size_t... I>
bool one_of_impl(const Array& arr, const UnaryPredicate& p,
std::index_sequence<I...>) {
bool found = false;
auto keep_searching = [&](const int n){
const bool p_res = found != p(n);
found = found || p_res;
return !found || p_res;
};
return (keep_searching(arr[I]) && ...) && found;
}
} // namespace detail
template <typename T, typename UnaryPredicate, std::size_t N,
typename Indices = std::make_index_sequence<N>>
auto one_of(const std::array<T, N>& arr,
const UnaryPredicate& p) {
return detail::one_of_impl(arr, p, Indices{});
}
int main() {
const std::array<int, 5> a{1, 3, 5, 6, 7};
std::cout << std::boolalpha << "Exactly one even number : "
<< one_of(a, [](const int n) {
return n % 2 == 0;
}); // Exactly one even number : true
}
This will also short-circuit upon early failure (“found more than one”), but will contain a few more simple boolean comparisons than in the approach above.
However, note that this approach could have its draw-backs, particularly for optimized code for container inputs with many elements, as is pointed out by #PeterCordes in a comment below. Citing the comment (as comments are not guaranteed to persist over time):
Just because the size is static doesn't mean that fully unrolling the loop with templates is a good idea. In the resulting asm, this needs a branch every iteration anyway to stop on found, so that might as well be a loop-branch. CPUs are good at running loops (code caches, loopback buffers). Compilers will fully unroll static-sized loops based on heuristics, but probably won't roll this back up if a is huge. So your first one_of implementation has the best of both worlds already, assuming a normal modern compiler like gcc or clang, or maybe MSVC

std::reduce with std::unordered_map

I have an unordered_map of vectors and I'm trying to use std::reduce to get the sum of all values in all vectors in the map. My current functional code (which I want to replace) looks like this:
// input is std::unordered_map<std::vector<uint64_t>>
template<typename T>
uint64_t get_map_sum(T& my_map)
{
uint64_t totalcount = 0;
for (auto& p : my_map)
{
for (const auto& q : p.second)
totalcount += q;
}
return total_count;
}
I'd like to replace this with std::reduce to utilize the parallel execution; I thought this would be straight forward as I only needed to replace each loop with a call to std::reduce, but this doesn't appear to be working. My attempt is this:
#include <numeric>
#include <execution>
#include <vector>
#include <unordered_map>
#include <cstdint>
// reduces the vectors
template <typename Iter, typename T>
T get_vector_sum(Iter begin, Iter end, T initial = 0)
{
return std::reduce(std::execution::par_unseq, begin, end, initial,
[&](auto cur, auto prev) { return cur + prev; });
}
// calls get_vector_sum for all vectors and then reduces vector sums
template<typename Iter>
uint64_t get_map_sum(Iter begin, Iter end)
{
return std::reduce(std::execution::par_unseq, begin, end, 0ULL,
[&](auto prev, auto cur)
{
return get_vector_sum<std::vector<uint64_t>::iterator,
uint64_t>(cur.begin(), cur.end(), prev);
//return get_vector_sum<std::vector<uint64_t>::iterator,
// uint64_t>(cur.second.begin(), cur.second.end(), prev);
});
}
With the code above, I get an error message saying error C2039: 'begin': is not a member of 'std::pair' referring to the auto cur in the lambda inside get_map_sum. I initially used cur as a std::pair, but when I did that I got a different error saying error C2228: left of '.second' must have class/struct/union.
int main()
{
std::unordered_map<uint64_t, std::vector<uint64_t>> in({
{1, std::vector<uint64_t>{1,2,3,4,5} },
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}}});
auto x = get_map_sum(in); // output 45
auto y = get_map_sum(in.begin(), in.end()); // error
return 0;
}
Is it possible to use std::reduce with maps like this and, if so, what changes do I need to make to get this working?
Note this requirements for binary_op of std::reduce:
binary FunctionObject that will be applied in unspecified order to the result of dereferencing the input iterators, the results of other binary_op and init.
This implies that the result of your lambda result and init needs to be of the same type as map's value type, i.e., std::pair<const uint64_t, std::vector<uint64_t>>.
You would therefore need to perform the outer reduction over values of this type, which would involve construction of new vectors.
I have also tried to create an exemplary code as follows:
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
using V = M::value_type;
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
auto p = std::reduce(in.begin(), in.end(), V{},
[](const V& a, const V& b) {
auto ra = std::reduce(a.second.begin(), a.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
auto rb = std::reduce(b.second.begin(), b.second.end(), 0UL,
[](uint64_t i1, uint64_t i2){ return i1 + i2; });
return V{0, { ra + rb }};
});
But it does not compile with GCC due to seemingly missing std::reduce implementation and Clang complains about missing copy assignment operator for value type, which is not copy-assignable due to const key: https://wandbox.org/permlink/FBYAhCArtOHvwu8C.
However, in cppreference, the requirements for the value type is only MoveConstructible, not Copy/MoveAssignable. So, there seems to be an incorrect implementation in libc++.
In this exemplary code, I was able to make it working by defning V without const as follows:
using V = std::pair<uint64_t, std::vector<uint64_t>>;
See https://wandbox.org/permlink/lF9VuJwISYXhpBJL.
Rather than constructing vectors as the intermediate result, we just need to provide a type implicitly convertible from M::value_type.
using M = std::unordered_map<uint64_t, std::vector<uint64_t>>;
template <typename Iter, typename T>
T par_unseq_sum(Iter begin, Iter end, T initial = 0)
{
// std::plus is the default reducer
return std::reduce(std::execution::par_unseq, begin, end, initial);
}
class map_vector_sum
{
public:
map_vector_sum() : sum(0) {}
map_vector_sum(M::const_reference elem) : sum(par_unseq_sum(elem.second)) {}
map_vector_sum& operator+(const map_vector_sum & rhs) { sum += rhs.sum; }
explicit operator uint64_t() { return sum; }
private:
uint64_t sum;
}
M in({ {1, std::vector<uint64_t>{1,2,3,4,5}},
{2, std::vector<uint64_t>{1,2,3,4,5}},
{3, std::vector<uint64_t>{1,2,3,4,5}} });
uint64_t sum = par_unseq_sum(in.begin(), in.end(), map_vector_sum());

Select specific elements from a vector

I have a vector v1, and a boolean vector v2 of the same size. I want to delete from v1 all values such that the parallel element of v2 is false:
vector<int> v3; // assume v1 is vector<int>
for (size_t i=0; i<v1.size(); i++)
if (v2[i])
v3.push_back(v1[i]);
v1=v3;
Is there a better way to do it?
in C++03
in C++11
size_t last = 0;
for (size_t i = 0; i < v1.size(); i++) {
if (v2[i]) {
v1[last++] = v1[i];
}
}
v1.erase(v1.begin() + last, v1.end());
Same as yours essentially, except it works in-place, not requiring additional storage. This is basically a reimplementation of std::remove_if (which would be difficult to use directly, because the function object it uses is given a value, not an index or iterator into the container).
In C++11 you can use std::remove_if and std::erase with a lambda, which is the "erase-remove-idiom":
size_t idx = 0;
v1.erase(std::remove_if(v1.begin(),
v1.end(),
[&idx, &v2](int val){return !v2[idx++];}),
v1.end())
And here's a link to it functioning as intended: cpp.sh/57jpc
As the comments point out however, there's a bit of discussion about the safety of doing it this way; the underlying assumption here is that std::remove_if will apply the predicate to the elements of v1 in order. However, the language in the doc doesn't explicitly guarantee this. It simply states:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. Relative order of the elements that remain is preserved and the physical size of the container is unchanged. Iterators pointing to an element between the new logical end and the physical end of the range are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition). A call to remove is typically followed by a call to a container's erase method, which erases the unspecified values and reduces the physical size of the container to match its new logical size.
Now, it would be difficult with only a forward iterator to a std::vector to both guarantee stability for results and not apply the predicate in-order. But it's certainly possible to do so.
A remove_if-based alternative is:
v1.erase(std::remove_if(v1.begin(), v1.end(),
[&v1, &v2](const int &x){ return !v2[&x - &v1[0]]; }),
v1.end());
Also consider that if you only need a view on v1 in which some elements are skipped, you can avoid to modify v1 and use something like boost::filter_iterator.
I hear you like lambdas.
auto with_index_into = [](auto&v){
return [&](auto&& f){
return [&,f=decltype(f)(f)](auto& e){
return f( std::addressof(e)-v.data(), e );
};
};
};
This may be useful. It takes a .data() suporting container, then returns a lambda of type ((Index,E&)->X)->(E&->X) -- the returned lambda converts an indexed element visitor to an element visitor. Sort of lambda judo.
template<class C, class Test>
auto erase_if( C& c, Test&& test) {
using std::begin; using std::end;
auto it=std::remove_if(begin(c),end(c),test);
if (it==end(c)) return false;
c.erase(it, end(c));
return true;
}
because I hate the remove erase idiom in client code.
Now the code is pretty:
erase_if( v1, with_index_into(v1)(
[](std::size_t i, auto&e){
return !v2[i];
}
));
The restriction on moves in remove/erase should mean it invokes the lambda on the element in its original position.
We can do this with more elemental steps. It gets complicated in the middle...
First, tiny named operator library:
namespace named_operator {
template<class D>struct make_operator{};
enum class lhs_token {
star = '*',
non_char_tokens_start = (unsigned char)-1,
arrow_star,
};
template<class T, lhs_token, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::star, Op>
operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::arrow_star, Op>
operator->*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::star, Op>&& lhs, Rhs&& rhs )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::arrow_star, Op>&& lhs, Rhs&& rhs )
{
return named_next( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
Now we define then:
namespace lambda_then {
struct then_t:named_operator::make_operator<then_t> {} then;
template<class Lhs, class Rhs>
auto named_next( Lhs&& lhs, then_t, Rhs&& rhs ) {
return
[lhs=std::forward<Lhs>(lhs), rhs=std::forward<Rhs>(rhs)]
(auto&&...args)->decltype(auto)
{
return rhs( lhs( decltype(args)(args)... ) );
};
}
}
using lambda_then::then;
which defines a token then such that lambda1 ->*then* lambda2 returns a function object that takes its arguments, passes it to lambda1, then passes the return value to lambda2.
Next we define to_index(container):
template<class C>
auto index_in( C& c ) {
return [&](auto& e){
return std::addressof(e)-c.data();
};
}
we also keep the above erase_if.
This results in:
erase_if( v1,
index_in(v1)
->*then*
[&](auto i){
return !v2[i];
}
);
solving your problem (live example).
I actually quite like the way you did it but I would make a couple of changes in limiting the scope the temporary vector is used and I would use std::vector::swap to avoid a copy at he end. If you have C++11 you could use std::move instead of std::vector::swap:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> iv = {0, 1, 2, 3, 4, 5, 6};
std::vector<bool> bv = {true, true, false, true, false, false, true};
// start a new scope to limit
// the lifespan of the temporary vector
{
std::vector<int> v;
// reserve space for performance gains
// if you don't mind an over-allocated return
// v.reserve(iv);
for(std::size_t i = 0; i < iv.size(); ++i)
if(bv[i])
v.push_back(iv[i]);
iv.swap(v); // faster than a copy
}
for(auto i: iv)
std::cout << i << ' ';
std::cout << '\n';
}
Different version that erases elements in place but does not require as many moves as Igor's algo requires and in case of small amount of elements to be erased could be more efficient:
using std::swap;
size_t last = v1.size();
for (size_t i = 0; i < last;) {
if( !v2[i] ) {
--last;
swap( v2[i], v2[last] );
swap( v1[i], v1[last] );
} else
++i;
}
v1.erase(v1.begin() + last, v1.end());
but this algo is unstable.
If you use a list (or forward_list for C++11) instead of a vector, you can do this in-place without the moving/allocating/copying overhead required for vector operations. It's perfectly possible to do most storage-related things with any STL container, but appropriate choice of containers will often give significant improvements in performance.

Splitting std::vector based on some criteria

I have a vector which contain some data. I want to split it into const number of vectors depending on some criteria. For example:
using Point=std::pair<int,int>;
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria);
int main(){
std::vector<Point> data;
//fill data
auto results=split_to_4(data,[](const Point& p){
if(cond1) return 0;
if(cond2) return 1;
if(cond3) return 2;
return 3;
});
}
What is the best way to implement split_to_4? My current attempt is:
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria){
std::array<std::vector<Point>,4> result;
for (const auto& p : data){
areas_regions[criteria(p)].emplace_back(p);
}
return result;
}
Any better.. More std way to do it?
By Better, I mean: more readable... depend on iterator... depend on some std functions...
You can do this in place with multiple calls to std::partition:
// Returns iterators to the three partition points in the range
template<class ForwardIt, class Which>
auto split4(ForwardIt first, ForwardIt last, Which which) {
std::array<ForwardIt, 3> ret;
ret[0] = std::partition(first, last,
[&](const auto &v){return which(v) == 0;});
ret[1] = std::partition(ret[0], last,
[&](const auto &v){return which(v) == 1;});
ret[2] = std::partition(ret[1], last,
[&](const auto &v){return which(v) == 2;});
return ret;
}
Of course you can also pass and use the conditions directly instead of proxiing through some which function if you so desire.
One could also trivially rewrite this with a loop to generalize it to splitN if necessary. (Watch out though, the complexity of this approach is O(N * n) for a range with n elements. This will probably be unreasonably slow for big N. On the other hand, we get swaps instead of copies, which may help if copying is expensive (compared to calling which). If performance is critical, measure.)
If you need the relative order of elements in each group preserved, std::stable_partition is your friend.
Just noticed the C++11 tag: The above code is C++14. For C++11 compatibility, simply change the autos I used to the explicit types, i.e. use std::array<ForwardIt, 3> as the return type and const std::iterator_traits<ForwardIt>::value_type& for the lambdas.
I'll leave that as is for brevity, this last paragraph completes the answer for the pre-C++14 folks.
update:
probably the most STL-like way:
Features:
Iterator-based so choice of source and destination containers is left to the caller
Source iterators may be move-iterators if move-partitioning is required, or leave as normal iterators to make a copy
Linear time complexity
Stable ordering of results (ref std::stable_partition)
-
#include <array>
#include <vector>
#include <utility>
#include <cassert>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class OutIter, class Which>
auto split_n(Iter first, Iter last,
OutIter outfirst, std::size_t N,
Which&& which)
{
while (first != last) {
auto index = which(*first);
assert (index < N);
std::next(outfirst, index) -> push_back(*first);
++ first;
}
}
template<class Iter, class OutIter, class Which>
auto split_to(Iter first, Iter last,
OutIter outfirst, OutIter outlast,
Which&& which)
{
return split_n(first, last, outfirst,
std::distance(outfirst, outlast),
std::forward<Which>(which));
}
int main(){
std::vector<Point> source;
std::array<std::vector<Point>, 4> dest { };
split_n(source.begin(), source.end(),
dest.begin(), dest.size(),
which_bucket);
// or
split_to(source.begin(), source.end(),
dest.begin(), dest.end(),
which_bucket);
// or with move request:
split_to(std::make_move_iterator(source.begin()),
std::make_move_iterator(source.end()),
dest.begin(), dest.end(),
which_bucket);
}
another way
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class Which>
auto split4(Iter first, Iter last, Which&& which)
{
std::array<std::vector<Point>, 4> result {};
while (first != last) {
result[which(*first)].push_back(*first);
++first;
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data.begin(), data.end(), which_bucket);
}
Here's another way which honours any custom allocator in the vector:
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class T, class A, class Which>
auto split4(const std::vector<T,A>& v,
Which&& which)
{
using vec_type = std::vector<T,A>;
std::array<std::vector<T,A>, 4> result {
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator())
};
for (auto& p : v) {
result[which(p)].push_back(p);
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data, which_bucket);
}

Find the nth element satisfying a condition?

Is there a couple of std::algorithm/lambda function to access the nth element satisfying a given condition. Because std::find_if will access the first one, so is there an equivalend to find the nth one ?
You need to create a stateful predicate that will count the number of instances and then complete when the expected count is reached. Now the problem is that there are no guarantees as of how many times the predicate will be copied during the evaluation of the algorithm, so you need to maintain that state outside of the predicate itself, which makes it a bit ugly, but you can do:
iterator which;
{ // block to limit the scope of the otherwise unneeded count variable
int count = 0;
which = std::find_if(c.begin(), c.end(), [&count](T const & x) {
return (condition(x) && ++count == 6)
});
};
If this comes up frequently, and you are not concerned about performance, you could write a predicate adapter that created a shared_ptr to the count internally and updated it. Multiple copies of the same adapter would share the same actual count object.
Another alternative would be to implement find_nth_if, which could be simpler.
#include <iterator>
#include <algorithm>
template<typename Iterator, typename Pred, typename Counter>
Iterator find_if_nth( Iterator first, Iterator last, Pred closure, Counter n ) {
typedef typename std::iterator_traits<Iterator>::reference Tref;
return std::find_if(first, last, [&](Tref x) {
return closure(x) && !(--n);
});
}
http://ideone.com/EZLLdL
An STL-like function template would be:
template<class InputIterator, class NthOccurence class UnaryPredicate>
InputIterator find_nth_if(InputIterator first, InputIterator last, NthOccurence Nth, UnaryPredicate pred)
{
if (Nth > 0)
while (first != last) {
if (pred(*first))
if (!--Nth)
return first;
++first;
}
return last;
}
And if you absolutely want to use the std::find_if, you could have something like:
template<class InputIterator, class NthOccurence class UnaryPredicate>
InputIterator find_nth_if(InputIterator first, InputIterator last, NthOccurence Nth, UnaryPredicate pred)
{
if (Nth > 0) {
do
first = std::find_if(first, last, pred);
while (!--Nth && ++first != last);
return first;
}
else
return last;
}
David's answer is fine as it is. Let me just point out that the predicate can be abstracted into the iterators by using the Boost.Iterator library, in particular the boost::filter_iterator adaptor, which has the advantage that it can be used for a lot more algorithms as well (counting e.g.):
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/iterator/filter_iterator.hpp>
template<class ForwardIt, class Predicate, class Size>
ForwardIt find_if_nth(ForwardIt first, ForwardIt last, Predicate pred, Size n)
{
auto vb = boost::make_filter_iterator(pred, first, last);
auto const ve = boost::make_filter_iterator(pred, last, last);
while (vb != ve && --n)
++vb;
return vb.base();
}
int main()
{
auto const v = std::vector<int>{ 0, 0, 3, 0, 2, 4, 5, 0, 7 };
auto const n = 2;
auto const pred = [](int i){ return i > 0; };
auto const nth_match = find_if_nth(v.begin(), v.end(), pred, n);
if (nth_match != v.end())
std::cout << *nth_match << '\n';
else
std::cout << "less than n elements in v matched predicate\n";
}
Live example. This will print 2 (the 2nd element > 0, counting starting at 1, so that find_if matches find_if_nth with n==1. If the predicate is changed to i > 10 or if the nth element is changed to n = 6, it will return the end iterator.