Rajat Gupta - 25 days ago 9
C++ Question

# Step/Stride Iterator for use with std::minmax_element

I have a 1D float array which represents a m *n (rows and columns) table of float values. My requirement is to find a min/max element for each row and column. For rows I can easily do it by using std::minmax_element by specifying a range of n elements. But for columns I need to use a stride iterator as elements are placed are not contiguous but placed at a step interval of n. Is there a standard iterator in boost/STL that can be used. The other option is to write my own version of it.
What is the best course ?

Two ways (among many) of doing it are using `range-v3` (or `boost::range`) and `boost::iterator`.

With `range-v3`, it's immediate:

``````#include <iostream>
#include <range/v3/all.hpp>

using namespace ranges;

int main() {
std::vector<std::size_t> src{1, 2, 3, 4, 5, 6, 7};
const auto min_max = minmax(src | view::stride(3));
std::cout << min_max.first << " " << min_max.second << std::endl;
}
``````

In `boost::range`, use `boost::adaptors::strided`.

``````#include <boost/range/adaptor/strided.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
using namespace boost::assign;

std::vector<int> input;
int arr[] = {1, 2, 3, 4, 5, 6, 7};

auto str = std::make_pair(&arr[0], &arr[8]) | strided(3);
std::cout << *boost::range::min_element(str) << " " << *boost::range::max_element(str) << std::endl;
}
``````

Note the following:

1. A range can be defined by a pair of iterators, so I used that here although a simpler form is possible (it fits your use case of heap-allocated C-style arrays).

2. Unfortunately, this sub-library doesn't seem to have min-max (or at least I couldn't find it), so there are two calls, one for min, and one for max.

Given a random-access iterator, it's not very difficult to build a strided forward `boost::iterator_facade`:

``````#include <iostream>
#include <vector>
#include <iterator>
#include <cstddef>
#include <algorithm>

template<typename It>
class stride_iterator :
stride_iterator<It>,
typename std::iterator_traits<It>::value_type,
boost::forward_traversal_tag> {
public:
stride_iterator() = default;
stride_iterator(It it, It end_it, std::size_t stride) :
m_it{it}, m_end_it{end_it}, m_stride{stride}
{}

private:
friend class boost::iterator_core_access;

void increment() {
if(std::distance(m_it, m_end_it) < m_stride) {
m_it = m_end_it;
return;
}
}

bool equal(const stride_iterator<It> &other) const {
return m_it == other.m_it;
}

typename std::iterator_traits<It>::value_type &dereference() const {
return *m_it; }

It m_it, m_end_it;
std::size_t m_stride;
};
``````

This should be enough for `std::minmax_element`. (Adding a bit of logic, the `decrement` and `advance` members, and changing the tag, would make it into a random-access iterator too.)

``````int main() {
using vec_t = std::vector<int>;
vec_t v{1, 2, 3, 4, 5, 6, 7};
stride_iterator<vec_t::iterator> b{std::begin(v), std::end(v), 3}, e{std::end(v), std::end(v), 3};
auto min_max = std::minmax_element(b, e);
std::cout << *min_max.first << " " << *min_max.second << std::endl;
}
``````