Думаю многие из тех, кто начали читать эту статью уже сталкивались с задачами сортировки массивов и прочих вещей, а так-же знают о том, что есть std::sort, но не все знают о существовании готовых предикатов.
Предикаты
Рассмотрим код на примере обычной сортировки вектора.
vector<int> v{ 14,3,-2,7 };
sort(v.begin(), v.end(), [](int a, int b) { return a > b; }); // 14 7 3 -2
Здесь с помощью лямбды мы сортируем вектор по убыванию, но что бы лишний раз не писать лямбду, можно просто написать предикат std::greater.
vector<int> v{ 14,3,-2,7 };
sort(v.begin(), v.end(), std::greater<int>{}); // 14 7 3 -2
Так-же существуют и другие, например std:less
или std::equal_to
Устройство подобных предикатов очень простое, создам свой аналог предиката std:less
template<typename T>
struct myless {
operator bool()(const T& lhs, const T& rhs) {
return lhs < rhs;
}
};
Использование подобной штуки очень простое
Для начала нам надо инициализировать объект, а далее уже использовать оператор круглые скобки. Например, предикат myless<int>{}(2,3)
будет равен true.
std::find_if, std::copy_if, ….
Задача: Даны два int вектора, нужно скопировать все положительные элементы из одного, в другой. Около года назад я бы сделал такую реализацию.
vector<int> from{ -5,2,6,-14,7 };
vector<int> to;
for (auto& el : from) {
if (el > 0)
to.push_back(el);
}
Но согласитесь, что код приведённый ниже будет смотреться гораздо элегантнее.
vector<int> from{ -5,2,6,-14,7 };
vector<int> to;
std::copy_if(from.begin(), from.end(), std::back_inserter(to),
[](int x) {return x > 0; });
Задача: Написать такую функцию с сигнатурой void foo(string&)
, что будет удалять все чары из строки не являющиеся какой-либо цифрой. Самое простое решение(логически) которое здесь только можно придумать
void foo(string& x) {
string temp = "";
for (auto& el : x) {
if (el >= '0' && el <= '9')
temp += el;
}
x = temp;
}
Думаю, что многие согласятся с тем, что выглядит это не очень то и красиво, поэтому предлагаю вариант немного получше.
void foo(string& x) {
std::erase_if(x, [](char s) {return !(s >= '0' && s <= '9'); });
}
Задача: Дан vector<int> и надо все отрицательные числа в нём заменить на нули. Реализация которую сделает большинство новичков, скорее всего будет выглядеть как-то так:
vector<int> x{ 2,-5,7,-3 };
for (auto& el : x) {
if (el < 0)
el = 0;
}
Здесь я нахожу более хороший вариант с использованием std::replace_if
vector<int> x{ 2,-5,7,-3 };
std::replace_if(x.begin(), x.end(), [](int x) {return x < 0; }, 0);
Задача: Функция string foo(string)
принимает как аргумент путь к файлу, а возвращает путь к папке, в которой он лежит.
cout << foo("C:\\Windows\\System32\\cmd.exe"); // C:\\Windows\\System32
Для совсем новичков не сходу будет понятно, как именно реализовать такую функцию. Но вспомнив о том, что у basic_string
есть метод rfind (поиск справа) можно легко справится с подобной задачей.
string foo(string x) {
return x.substr(0, x.rfind("\\"));
}
Здесь rfind ищет самое первое вхождение подстроки "\\" с конца(справа) исходной строки.