I previously posted a question on finding the maximum value of an InputIterator
range. For completeness, I thought it would be useful to post an implementation that finds the minimum & maximum values, in a similar way to std::minmax_element
.
#include <iterator>
#include <algorithm>
#include <functional>
#include <utility>
namespace detail
{
template <typename InputIt, typename Compare>
auto minmax_input(InputIt first, InputIt last, Compare comp, std::input_iterator_tag)
{
using ValueType = typename std::iterator_traits<InputIt>::value_type;
std::pair<ValueType, ValueType> result {*first, *first};
if (++first == last) return result;
if (comp(*first, result.first)) {
result.first = *first;
} else {
result.second = *first;
}
while (++first != last) {
auto prev = *first;
if (++first == last) {
if (comp(prev, result.first))
result.first = std::move(prev);
else if (!comp(prev, result.second))
result.second = std::move(prev);
break;
} else {
if (comp(*first, prev)) {
if (comp(*first, result.first))
result.first = *first;
if (!comp(prev, result.second))
result.second = std::move(prev);
} else {
if (comp(prev, result.first))
result.first = std::move(prev);
if (!comp(*first, result.second))
result.second = *first;
}
}
}
return result;
}
template <typename ForwardIt, typename Compare>
auto minmax_input(ForwardIt first, ForwardIt last, Compare comp, std::forward_iterator_tag)
{
const auto itr_result = std::minmax_element(first, last, comp);
return std::make_pair(*itr_result.first, *itr_result.second);
}
} // namespace detail
template <typename InputIt, typename Compare = std::less<void>>
auto minmax_input(InputIt first, InputIt last, Compare comp = Compare {})
{
return detail::minmax_input(first, last, comp, typename std::iterator_traits<InputIt>::iterator_category {});
}
As this will presumably be used mostly on input streams, I also thought to provide this helper method:
#include <istream>
template <typename T>
auto minmax_stream(std::istream& in)
{
return minmax_input(std::istream_iterator<T> {in}, std::istream_iterator<T> {});
}
Used like:
#include <iostream>
#include <sstream>
int main()
{
std::istringstream ss {"0.1 0.2 0.3 0.4 0.2 0.05 0.1"};
const auto minmax = minmax_stream<double>(ss);
std::cout << "minmax is (" << minmax.first << ", " << minmax.second << ")" << std::endl;
}
auto
) or (as your reference shows) try and keep the iterator before it was advanced - comment your choice? Nagging me in both renditions is the repetition of the non-pair comparisons at the beginning and end of the sequence - beware a non-answer. – greybeard Feb 10 at 11:46