#c #algorithm #stl
#c #алгоритм #stl
Вопрос:
Так же, как в STL есть алгоритмы count_if и remove_if, я хотел бы найти что-то вроде execute_if , который принимал бы предикат условия отдельно от выполняемой функции.
Например, я хотел бы получить 1 строку, которая печатает все коэффициенты, используя 2 лямбды, что-то вроде этого:
auto vec = vector<int>{ 1,2,3,4,5 };
for_each_if(vec.begin(), vec.end(), [](auto val) {return val % 2 != 0; }, [](auto val) { cout << val; });
Какой хороший способ сделать это с помощью алгоритмов?
Комментарии:
1. Почему такой алгоритм существует сегодня? Функтор может буквально делать все , и с помощью лямбд мы можем легко создавать существующие функторы.
2.
std::for_each
и лямбда, который содержитif
? Это намного понятнее, чем ваше предложение.3. Чем
execute_if
функция будет отличаться от обычногоif
оператора?4. разделение проблем. Например: один вызывающий отправил бы ifodds, другой вызывающий отправил бы ifevens. Оба отправили бы принтер. Или один вызывающий отправляет numberprinter, другой отправляет что-то еще. Оба отправили бы ifodds.
5. Зачем вам нужны два лямбда? Начиная с C 11,
std::copy_if(vec.begin(), vec.end(), std::ostream_iterator(std::cout, " "), [](auto val) {return val %2 != 0;})
будет делать то, что вы ищете (при условии, что вы хотите пробелы между выходными значениями).
Ответ №1:
Если у вас есть поддержка C 20, вы можете использовать новую range-library:
std::vector<int> vec{ 1,2,3,4,5 };
for (auto val : vec | std::views::filter([](auto val) { return val % 2 != 0; }))
{
std::cout << val;
}
Или (конечно):
std::vector<int> vec{ 1,2,3,4,5 };
auto filtered = vec | std::views::filter([](auto val) {return val % 2 != 0; });
std::for_each(filtered.begin(), filtered.end(), [](auto val) { std::cout << val; } );
Ответ №2:
Вы могли бы написать такой алгоритм самостоятельно:
#include <iostream>
#include <algorithm>
#include <vector>
template <typename IT,typename predicate,typename func>
void for_each_if(IT begin,IT end,predicate p, func f){
std::for_each(begin,end,[amp;f,amp;p](auto val){
if (p(val)) f(val);
});
}
int main() {
auto vec = std::vector<int>{ 1,2,3,4,5 };
for_each_if(vec.begin(), vec.end(), [](auto val) {return val % 2 != 0; }, [](auto val) { std::cout << val; });
}
Однако будьте готовы к обсуждению того, какой из них на самом деле более удобочитаем. Я определенно предпочитаю передавать только один функтор for_each
вместо передачи двух функторов for_each_if
.
разделение проблем. Один вызывающий отправил бы ifodds, другой вызывающий отправил бы ifevens. Оба отправили бы принтер.
Для этого вам не нужен дополнительный алгоритм. Альтернативой вышеупомянутому является:
auto condition = [](auto val) {return val % 2 != 0; };
auto func = [](auto val) { std::cout << val; };
auto if_fun = [amp;condition,amp;func](auto val){ if (condition(val)) func(val);};
std::for_each(vec.begin(),vec.end(),if_fun);
Вы можете составлять if_fun
из разных предикатов и разных функций по своему усмотрению.
Комментарии:
1. Это вопрос удобства и ясности. Тогда, по вашей логике, нам не нужен count_if. Я могу просто выполнить foreach и посчитать совпадения самостоятельно.
2. @GonenI причина использования стандартных алгоритмов заключается в удобочитаемости и выразительности, но это преимущество проистекает главным образом из того факта, что они являются стандартными. Вы можете изобрести самый хороший алгоритм, который вы считаете суперчитаемым, но трудно конкурировать со стандартными алгоритмами, которые все знают, документация повсюду, и они протестированы и отлажены миллионами пользователей
3. @GonenI во всяком случае, я не имел в виду это «По вашей логике, тогда нам не нужен count_if». Если вы прочитали это в ответе, то, возможно, я недостаточно хорошо объяснил себя