1

Let us assume we have a vector of vectors and wish to find a minimum (or maximum) values (no need to know their position in the table). What would be an elegant way to accomplish this?

The obvious solution, included below, is to run std::min_element per each row in a loop. But may be it is possible to do it with a single statement without loop using, may be, lambda functions?

Note, there is a similar question on SO already, but it is actually not quite about what I am asking here.

Update: Ideal solution would be using STL only, but, failing that, it would be interesting to see other options.

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<double> > test_array=
         {
          {1., 2., 3., 4.},
          {7., 4., 6., 8.},
          {5., -1., 3., 1}
         };
    double min_val(test_array[0][0]);
    double max_val(test_array[0][0]);
    for(auto& row : test_array)
    {
        min_val = std::min(min_val, *std::min_element(row.begin(), row.end()));
        max_val = std::max(max_val, *std::max_element(row.begin(), row.end()));
    }

    cout << "Minimum = " << min_val << std::endl;
    cout << "Maximum = " << max_val << std::endl;
    return 0;
}
5
  • The issue is that the algorithms return an iterator, so you can't do std::max_element(begin(array), end(array), 0, [](){}) because you would need to return an iterator on a vector, and not on an element :/ Commented Dec 12, 2018 at 11:25
  • 3
    With range-v3, there is ranges::view::join to see the range of ranges as flattened range, then a simple std::minmax_element would be sufficient. Commented Dec 12, 2018 at 11:28
  • @Jarod42 Any chance for an answer based on it? Commented Dec 12, 2018 at 11:31
  • @MatthieuBrucher: unsure it is fine for OP to use external lib. Commented Dec 12, 2018 at 11:32
  • I would vote for @Jarod42. Find a way to view the vector of vector by one iterator. This could be done some iterator that knows about all vectors. Or you drop the vector of vector for a simple vector. Commented Dec 12, 2018 at 12:52

2 Answers 2

2

With range-v3, you might have a flatten view with ranges::view::join:

std::vector<std::vector<double> > test_array =
{
    {1., 2., 3., 4.},
    {7., 4., 6., 8.},
    {5., -1., 3., 1}
};
auto flatten_view = test_array | ranges::view::join;
const auto p = std::minmax_element(begin(flatten_view), end(flatten_view));
std::cout << "Minimum = " << *p.first << std::endl;
std::cout << "Maximum = " << *p.second << std::endl;

Demo

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I upvoted your solution as it is definitely elegant and easy to understand, although it is outside the STL at the moment. Well, I guess one cannot have both.
1

There are multiple options, e.g., the following one uses std::accumulate that returns pair of numbers containing minimum and maximum elements, respectively:

auto res = std::accumulate(a.begin(), a.end(), std::make_pair(a[0][0], a[0][0]),
    [](const auto& current, const auto& v) {
        auto minmax = std::minmax_element(v.begin(), v.end());
        return std::make_pair(std::min(current.first, *minmax.first),
                              std::max(current.second, *minmax.second));
    });

Live demo: https://wandbox.org/permlink/IwMWioewJBg7C67l

2 Comments

Interesting solution. I accept is as an answer as it is formally correct. Basically it answers my question -- it is possible, but the result is neither elegant nor easy to understand. Thank you.
@one_two_three Agree, we cannot have both. Hopefully, ranges will get into C++20.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.