Rationale
Consider we have some data sequence (vector-like), for example: [2, 1, 3, 4, 5, 0, 0, 1]. Second, we have some predicate, which can be applied to sequence element, for example: bool f(int a) { return a < 3; }. So we wish get all ranges (indexes pairs) which elements satisfy defined predicate.
For given example we have following pairs: {0, 3}; {5,8}.
Note: Pairs describes range in STL manner: [a, b).
Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<typename It1, typename It2, typename Pred1>
void getRangesIf (It1 first, It1 last, It2 dst_first, Pred1 f)
{
for (auto it = first, jt = first; it != last;) {
it = std::find_if (it, last, f);
jt = std::find_if_not (it, last, f);
if (it != jt) {
const auto fst_ind = std::distance (first, it);
const auto snd_ind = std::distance (first, jt);
*dst_first++ = std::make_pair (fst_ind, snd_ind);
}
std::swap (it, jt);
}
}
Notes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | template<typename It1, typename It2, typename Pred1> void getRangesIf (It1 first, It1 last, It2 dst_first, Pred1 f) { for (auto it = first, jt = first; it != last;) { it = std::find_if (it, last, f); jt = std::find_if_not (it, last, f); if (it != jt) { const auto fst_ind = std::distance (first, it); const auto snd_ind = std::distance (first, jt); *dst_first++ = std::make_pair (fst_ind, snd_ind); } std::swap (it, jt); } } |
Algorithm written for C++11 environment and can be ported to C++03, but who cares ?
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #include <iostream> #include <sstream> #include <algorithm> #include <iterator> #include <vector> typedef std::pair<size_t , size_t> RangePair; typedef std::vector<rangepair> RangeVec; template<typename It1, typename It2, typename Pred1> void getRangesIf (It1 first, It1 last, It2 dst_first, Pred1 f) { for (auto it = first, jt = first; it != last;) { it = std::find_if (it, last, f); jt = std::find_if_not (it, last, f); if (it != jt) { const auto fst_ind = std::distance (first, it); const auto snd_ind = std::distance (first, jt); *dst_first++ = std::make_pair (fst_ind, snd_ind); } std::swap (it, jt); } } const size_t kVecSz = 1024; int main() { std::vector<int> some_vec (kVecSz); std::generate (std::begin (some_vec), std::end (some_vec), rand); RangeVec ranges; getRangesIf (std::begin (some_vec), std::end (some_vec), std::back_inserter<decltype (ranges) > (ranges), [] (int elem) { return elem < (RAND_MAX / 2); }); std::cout << "Less than (RAND_MAX/2) ranges: \n"; std::for_each(std::begin(ranges), std::end(ranges), [](RangePair p) { std::cout << "[" << p.first << ", " << p.second << "]\n"; }); std::cin.get(); } |
Possible output