Поиск максимума и минимума в векторе пользовательских данных с использованием алгоритма

У меня есть такая структура данных:

struct Speed {

       int set; //set by user
       int act; //actual speed
       int millis; //millis since epoch
}

vector<Speed> data;

Теперь я хочу нарисовать этот вектор. Чтобы создать красивую ось, я хочу найти максимум и минимум данных в этом векторе. Мне это нравится, но, очевидно, поскольку оно основано только на set, оно подведет меня, если в какой-то момент act будет меньше или больше, чем set. Я имею в виду, что ось Y диаграммы должна быть между минимумом set, act и максимумом set, act.

auto max = std::max_element(begin(data), end(data),
                            [&](const Speed& a, const Speed& b){
    return a.set() < b.set(); 
    //how about act?
});

auto min = std::min_element(begin(data), end(data),
                            [&](const Speed& a, const Speed& b){
    return a.set() < b.set();
    //how about act?
});

**Я ЗНАЮ**, как написать нормальный код без использования алгоритма и лямбда-выражений для достижения результата... но мне интересно посмотреть, как это можно сделать с алгоритмом/лямбдой БЕЗ перегрузки оператора в структуре.

Я мог бы также сделать то же самое для act, а затем сравнить результаты... но это стоило бы мне 4 циклов!


person Saeid Yazdani    schedule 09.10.2017    source источник
comment
Непонятно, как вы хотите, чтобы сравнение действовало? Вы хотите самый маленький / самый большой набор и действие? Среднее? Минимум/максимум суммы set и act? Есть много способов сравнить два значения.   -  person Jonesinator    schedule 09.10.2017
comment
@Jonesinator Я просто хочу, чтобы моя диаграмма охватывала оба диапазона значений минимума и максимума.   -  person Saeid Yazdani    schedule 09.10.2017
comment
Ваш вопрос о построении функции сравнения для двух свойств (set, act)?   -  person Olha    schedule 09.10.2017
comment
Вы хотите, чтобы элементы min/max были установлены, а также элементы min/max были установлены, или чтобы элементы min/max были установлены как для и действия?   -  person Daniel    schedule 09.10.2017
comment
@ Даниэль с обоими, конечно!   -  person Saeid Yazdani    schedule 09.10.2017
comment
но вы знаете о том, что max/min_element возвращает итератор к одному из элементов коллекции?   -  person W.F.    schedule 09.10.2017
comment
Очевидно, вы не можете вернуть 2 значения из одного и того же вызова std::min_element... Но вы можете получить и минимальное, и максимальное значение в одном цикле с помощью std::minmax_element.   -  person Phil1970    schedule 09.10.2017
comment
@В.Ф. да, поэтому я хочу, чтобы он получил для элемента, у которого есть максимум между набором и действием, а другой - для минимума между набором и действием   -  person Saeid Yazdani    schedule 09.10.2017
comment
@SaeidYazdani, о, это прояснило ... посмотрите ответ Jonesinator, потому что это может быть то, что вы хотите   -  person W.F.    schedule 09.10.2017
comment
@SaeidYazdani Вы должны с самого начала написать четкий вопрос. Этот вопрос написан очень плохо. Постарайтесь задать хороший вопрос. Если вы не умеете задавать вопросы, то следует привести пример или два входных данных и желаемого результата.   -  person Phil1970    schedule 09.10.2017
comment
@Phil1970 ты прав...   -  person Saeid Yazdani    schedule 09.10.2017


Ответы (2)


Как правило, я бы рекомендовал наиболее читаемый код.

Таким образом, это будет что-то вроде (при условии наличия хотя бы одного элемента):

auto set_minmax = std::minmax_element(begin(data), end(data),
    [&](const Speed& a, const Speed& b) { return a.set < b.set; });

auto act_minmax = std::minmax_element(begin(data), end(data),
    [&](const Speed& a, const Speed& b) { return a.act < b.act; });

auto min_act_set = std::min(*set_minmax.first, *act_minmax.first);
auto max_act_set = std::max(*set_minmax.second, *act_minmax.second);

Однако, если данные действительно большие или логика более сложная, я бы рекомендовал иметь объект, который накапливает статистику и выполняет какой-то цикл по данным.

person Phil1970    schedule 09.10.2017
comment
Я действительно использовал свой собственный цикл, потому что в противном случае я мог бы получить в 2 раза больше вызовов для получения значения (с двумя общими указателями) вместо одного в моем цикле. Небольшая оптимизация, но с течением времени, это еще довольно много циклов сохранено. - person Alexis Wilke; 16.09.2018

Вы можете использовать std::min и std::max внутри своих вызовов std::min_element и std::max_element.

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

struct Speed {
       int set;
       int act;
       int millis;
};

int main() {
    std::vector<Speed> data = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    auto max_val = std::max_element(begin(data), end(data),
                                    [](const Speed& a, const Speed& b){
        return std::max(a.set, a.act) < std::max(b.set, b.act);
    });

    auto min_val = std::min_element(begin(data), end(data),
                                    [](const Speed& a, const Speed& b){
        return std::min(a.set, a.act) < std::min(b.set, b.act);
    });

    std::cout << "MAX: " << max_val->set << " " << max_val->act << "\n";
    std::cout << "MIN: " << min_val->set << " " << min_val->act << "\n";
}

Один проход с std::minmax здесь не сработает. Каждое сравнение элементов должно возвращать логическое значение, где true означает, что левая часть меньше правой, а false означает, что левая часть больше или равна правой части (т. е. требуется строгий слабый порядок). Однако здесь один элемент может быть как меньше , так и больше другого элемента. Вы можете легко написать свою собственную функцию для создания minmax_element за один проход, но я не думаю, что она хорошо вписывается в существующие функции STL без двух проходов.

person Jonesinator    schedule 09.10.2017
comment
Если это то, чего хочет OP в результате, то я бы использовал std::minmax_element для каждого члена, а затем получил окончательный минимум и максимум. Наверное, легче читать и эффективнее. - person Phil1970; 09.10.2017
comment
С некоторыми изменениями onlinegdb.com/SJZCyXKhb это близко к тому, что я имел в виду... но было бы неплохо, если бы это можно сделать только в один цикл - person Saeid Yazdani; 09.10.2017
comment
Я думаю, что подход с одним циклом не будет правильно обрабатывать все случаи. Например, будет ли это работать, если один и тот же элемент является как минимумом для одного поля, так и максимумом для другого поля. - person Phil1970; 09.10.2017
comment
Да, на самом деле @Phil1970 прав, реализация std::minmax_element работает не во всех случаях. - person Jonesinator; 09.10.2017
comment
да, в некоторых случаях это не удалось! - person Saeid Yazdani; 12.10.2017