Find the nth element satisfying a condition? - c++

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.

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

Find equal range for container with string with prefix

I am having 2 iterators range_begin,range_end, which are my container. I need to find all string which start with char prefix.
Here is my code:
template <typename RandomIt>
pair<RandomIt, RandomIt> FindStartsWith(
RandomIt range_begin, RandomIt
range_end,char prefix){
auto it=equal_range(range_begin,range_end,prefix,
[prefix](const string& city){return city[0]==prefix;});
return it;}
For example, for
const vector<string> sorted_strings = {"moscow", "murmansk", "vologda"};
auto it=FindStartsWith(strings.begin(),strings.end(),'m');
I want to get iterator with first on "moscow" and last after "murmansk".
I am getting strange compilier errors. What is wrong and how can I solve this?I cannot write correct lambda comporator.
equal_range expects a comparison function that takes two parameters; you are passing a function taking one.
A heterogeneous call (one where the type of value is not the same as the type elements in the range) requires a comparison function that can take the two types in either order. A lambda won't work in this case as it only has one operator() overload.
Finally, the function must perform a less-than type of comparison, not an equals one. Roughly, equal_range returns a range from the first element for which !(element < value) to the first element for which value < element.
Your errors might be due to strings.begin() and .end() which do not have sorted_. I do not think you should use a template either. Errors aside, I recommend you use a different std function. A simpler solution is to use foreach:
#include <algorithm>
#include <iterator>
#include <list>
#include <string>
#include <utility>
#include <vector>
typedef std::vector<std::string>::const_iterator RandomIt;
std::vector<std::string> FindStartsWith(RandomIt start, RandomIt end, const char prefix) {
std::vector<std::string> result;
std::for_each(start, end, [&](auto city) {
if (city.front() == prefix) {
result.push_back(city);
}
});
return result;
}
int main(int argc, char* argv[]) {
const std::vector<std::string> sorted_strings = { "moscow", "murmansk", "vologda" };
auto prefix_cities = FindStartsWith(sorted_strings.begin(), sorted_strings.end(), 'm');
return 0;
}
Definitely could use a refactor, but I'm assuming you need to implement it in the FindStartsWith for some other reason...
Thanks for posting, this taught me a lot about equal_range :)
ANSWER:
The reason for your compile error is hidden in the implementations of comparators in two functions "lower_bound" and "upper_bound" which call from the main function "equal_range".
EQUAL_RANGE
template<class ForwardIt, class T, class Compare>
pair<ForwardIt,ForwardIt>
equal_range(ForwardIt first, ForwardIt last,
const T& value, Compare comp)
{
return make_pair(lower_bound(first, last, value, comp),
upper_bound(first, last, value, comp));
}
Make attention to how the comparator is caused in each function. Look that comparators are caused by different sequences of arguments and this is the reason for the error.
LOWER_BOUND:
if (comp(*it, value))
UPPER_BOUND:
if (!comp(value, *it))
ADDITIONAL INFOMATION
Below I copied an example of implementations of two functions accordingly.
LOWER_BOUND:
```
template<class ForwardIt, class T, class Compare>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
ForwardIt it;
typename std::iterator_traits<ForwardIt>::difference_type count, step;
count = std::distance(first, last);
while (count > 0) {
it = first;
step = count / 2;
std::advance(it, step);
if (comp(*it, value)) {
first = ++it;
count -= step + 1;
}
else
count = step;
}
return first;
}
```
UPPER_BOUND:
```
template<class ForwardIt, class T, class Compare>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
ForwardIt it;
typename std::iterator_traits<ForwardIt>::difference_type count, step;
count = std::distance(first, last);
while (count > 0) {
it = first;
step = count / 2;
std::advance(it, step);
if (!comp(value, *it)) {
first = ++it;
count -= step + 1;
}
else
count = step;
}
return first;
}
```
SOLUTION
You have two ways to solve this problem (maybe more).
Write two comparators for each function and call each other separatively.
Convert char argument to string, write comparator for strings and call equal_range.

c++ STL min_element

I want to find the minimum element in an array, but if the minimum element appears more than once, then I want the last occurrence of the element. I used std::min_element() with my comp() function.
vector<int>::iterator it=min_element(input.begin(), input.end(),comp);
cout << *it << endl;
cout << distance(input.begin(), it);
bool comp(int a, int b) {
if (a <= b)
return true;
else
return false;
}
This code is giving an error saying invalid comparator on input 3 3 4.
Give min_element reverse iterators instead:
vector<int>::reverse_iterator it=min_element(input.rbegin(), input.rend(),comp);
Then convert it back to a "normal" iterator iff you need to.
And don't forget to correct your comparator; it needs to be < not <=.
You might abuse of std::minmax_element which returns the last biggest element contrary to std::max_element:
auto last_min_it = std::minmax_element(input.begin(), input.end(), std::greater<>{}).second;
I would probably use reverse iterator with std::min_element, though:
auto min_rev_it = std::min_element(input.rbegin(), input.rend());
If your data are stored in a vector, then the use of a reverse iterator should suffice, as already suggested.
More generally, the Standard Library does not provide a min_element_last function, as also commented in 1. In this respect, a possible implementation of min_element_last may read:
template <typename I>
using ValueType = typename std::iterator_traits<I>::value_type;
template <typename I, typename R>
// I models ForwardIterator
// R models StrictWeakOrdering on ValueType<I>
I min_element_last(I first, I last, R cmp) {
if (first == last) return last;
I curr = first;
++first;
while (first != last) {
if (!cmp(*curr, *first)) {
curr = first;
}
++first;
}
return curr;
}
template <typename I>
// I models ForwardIterator
// ValueType<I> models TotallyOrdered
I min_element_last(I first, I last) {
using T = ValueType<I>;
return min_element_last(first, last, std::less<T>());
}
The advantage would be the possibility of using min_element_last also with iterators that only model the ForwardIterator concept.

Move all elements which satisfy some condition from one container to another, i.e. I'm looking for some kind of "move_if"

Given
std::vector<T> first = /* some given data */, second;
I want to move all elements e which satisfy some condition cond(e) from first to second, i.e. something like
move_if(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::back_inserter(second), [&](T const& e)
{
return cond(e);
});
I wasn't able to establish this with the algorithms library. So, how can I do that?
If the moved-from elements can stay where they are in first, then just use copy_if with move_iterator.
std::copy_if(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::back_inserter(second), cond);
If the moved-from elements should be erased from first, I'd do
// partition: all elements that should not be moved come before
// (note that the lambda negates cond) all elements that should be moved.
// stable_partition maintains relative order in each group
auto p = std::stable_partition(first.begin(), first.end(),
[&](const auto& x) { return !cond(x); });
// range insert with move
second.insert(second.end(), std::make_move_iterator(p),
std::make_move_iterator(first.end()));
// erase the moved-from elements.
first.erase(p, first.end());
Or partition_copy with a move_iterator, followed by assignment:
std::vector<T> new_first;
std::partition_copy(std::make_move_iterator(first.begin()),
std::make_move_iterator(first.end()),
std::back_inserter(second), std::back_inserter(new_first), cond);
first = std::move(new_first);
The reason why move_if doesn't exist is because it would bloat the library. Either use copy_if with move iterator or write it yourself.
copy_if(move_iterator<I>(f), move_iterator<I>(l), out);
Here is an implementation by Jonas_No found at channel9.
template <typename FwdIt, typename Container, typename Predicate>
inline FwdIt move_if(FwdIt first, FwdIt last, Container &cont, Predicate pred)
{
if (first == last)
return last; // Empty so nothing to move
const size_t size = count_if(first, last, pred);
if (size == 0)
return last; // Nothing to move
cont.resize(size);
FwdIt new_end = first;
auto c = cont.begin();
for (auto i = first; i != last; ++i)
{
if (pred(*i)) // Should it move it ?
*c++ = move(*i);
else
*new_end++ = move(*i);
}
return new_end;
}
#T.C. has provided a perfectly working solution. However, at a first glance, one may not understand what the intend of that code is. So, it might be not perfect, but I tend to prefer something like this:
template<class InputIt, class OutputIt, class InputContainer, class UnaryPredicate>
OutputIt move_and_erase_if(InputIt first, InputIt last, InputContainer& c, OutputIt d_first, UnaryPredicate pred)
{
auto dist = std::distance(first, last);
while (first != last)
{
if (pred(*first))
{
*d_first++ = std::move(*first);
first = c.erase(first);
last = std::next(first, --dist);
}
else
{
++first;
--dist;
}
}
return d_first;
}

Remove elements from range and copy removed elements to new range

I need a method to remove all elements fulfilling a certain criteria from a range (an std::vector in this particular case) and copy those removed elements to a new range (so something like std::remove_if with an output parameter.) Neither the order of the input range nor the order of the output range after this operation is relevant.
One naive approach would be using std::partition to find all "evil" elements, then copy those and last remove them, but this would touch all the "evil" elements twice without need.
Alternatively I could write the desired remove_if variant myself, but why reinvent the wheel (plus I do not know if I can match the efficiency of a high quality library implementation).
So the question is:
Does a such a function already exist?
Boost is allowed, but standard C++ is preferred (the project does not depend on boost yet).
If not, is there a smart algorithm that is faster than a naive handcrafted remove_if variant would be?
No it doesn't. There's functions that do one (remove elements which match a predicate) or the other (copy elements which match a predicate) but not both. But it's easy enough to write our own in two steps:
template <typename InputIter, typename OutputIter, typename UnaryPredicate>
InputIter remove_and_copy(InputIter first, InputIter last,
OutputIter d_first, UnaryPredicate pred)
{
std::copy_if(first, last, d_first, pred);
return std::remove_if(first, last, pred);
}
To be used like:
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7};
std::vector<int> u;
v.erase(
remove_and_copy(v.begin(), v.end(), std::back_inserter(u),
[](int i) { return i%2 == 0; }),
v.end()
);
// now v is {1, 3, 5, 7} and u is {2, 4, 6}
If you only need vector you can write it a bit differently, but still just 2 lines:
template <typename T, typename UnaryPredicate>
void remove_and_copy(std::vector<T>& from, std::vector<T>& to, UnaryPredicate pred)
{
std::copy_if(from.begin(), from.end(), std::back_inserter(to), pred);
from.erase(std::remove_if(from.begin(), from.end(), pred), from.end());
}
Or write your own loop:
template <typename T, typename UnaryPredicate>
void remove_and_copy(std::vector<T>& from, std::vector<T>& to, UnaryPredicate pred)
{
for (auto it = from.begin(); it != from.end(); ) {
if (pred(*it)) {
to.push_back(*it);
it = from.erase(it);
}
else {
++it;
}
}
}
Usage of either:
remove_and_copy(v, u, [](int i) { return i%2 == 0; });
The problem with removing while using iterators is that you don't have access to the actual container, so you can't actually get rid of the elements. Rather, for instance, what std::remove() does is move the target range to the end of the range, which the container will later use to actually remove the elements.
Instead, you can have your function take the stream as a parameter so you can call its removal method once the target value is found:
#include <algorithm>
#include <iterator>
#include <string>
#include <iostream>
template <typename Container, typename OutputIt, typename UnaryPredicate>
auto remove_and_copy_if(Container& c, OutputIt d_first, UnaryPredicate pred)
-> decltype(c.begin())
{
auto it = std::begin(c);
for (; it != std::end(c); )
{
while (it != std::end(c) && pred(*it))
{
d_first++ = *it;
it = c.erase(it);
}
if (it != std::end(c)) ++it;
}
return it;
}
template <typename Container, typename OutputIt, typename T>
auto remove_and_copy(Container& c, OutputIt d_first, T const& value)
-> decltype(c.begin())
{
return remove_and_copy_if(c, d_first,
[&] (T const& t) { return t == value; });
}
int main()
{
std::string str = "Text with some spaces ";
std::string output;
std::cout << "Before: " << str << '\n';
remove_and_copy(str, std::back_inserter(output), ' ');
std::cout << "After: " << str << '\n';
std::cout << "Characters removed: " << output << '\n';
}
Demo