Как стать автором
Обновить

Использование алгоритмов стандартой библиотеки вместо циклов

Думаю многие из тех, кто начали читать эту статью уже сталкивались с задачами сортировки массивов и прочих вещей, а так-же знают о том, что есть 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 ищет самое первое вхождение подстроки "\\" с конца(справа) исходной строки.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.