8. Далее снова реализуем предикат для нечетных чисел и еще одну функцию-предикат, которая решает прямо противоположную задачу: сообщает, является ли заданное число четным:
auto odd_number ([](int i) { return i % 2 != 0; });
auto even_number ([](int i) { return i % 2 == 0; });
9. Следующие две строки делают одно и то же: копируют
v2
и v3
. В первой строке это делается с помощью алгоритма std::remove_copy_if
, копирующего все из исходного контейнера в другой контейнер, который std::copy_if
, который копирует все значения, remove_copy_if(begin(v), end(v),
back_inserter(v2), odd_number);
copy_if(begin(v), end(v),
back_inserter(v3), even_number);
10. Вывод на экран двух векторов должен дать одинаковый результат:
print(v2);
print(v3);
}
11. Скомпилируем и запустим программу. В первой строке показан вектор после инициализации. Во второй — вектор, из которого мы удалили все значения 2
4
на значения 123
.В последних двух строках показываются векторы v2
v3
:$ ./removing_items_from_containers
1, 2, 3, 4, 5, 6,
1, 3, 4, 5, 6,
4, 6,
123, 6,
2, 4, 6, 8, 10,
2, 4, 6, 8, 10,
Как это работает
Мы использовали различные алгоритмы, связанные с фильтрацией данных (табл. 5.2).
Для каждого из перечисленных алгоритмов существует версия *_if
Преобразуем содержимое контейнеров
Если std::copy
std::transform
— второй по сложности алгоритм STL. Как и copy, он копирует элементы из одного диапазона данных в другой, но дополнительно принимает функцию преобразования. Она может изменить значение выходного типа до того, как это значение окажется в выходном диапазоне. Более того, данная функция может создать значение совершенно другого типа, что может быть полезно, если входной и выходной диапазоны данных имеют разные типы. Этот алгоритм прост в использовании, но в то же время очень полезен, вследствие чего он становится стандартным компонентом, который можно применять во многих повседневных программах.Как это делается
В этом примере мы воспользуемся алгоритмом std::transform
1. Как обычно, сначала включим все необходимые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
#include
#include
#include
#include
using namespace std;
2. В качестве примера исходной структуры данных возьмем вектор, содержащий простые целые числа:
int main()
{
vector
3. Теперь скопируем все элементы в итератор вывода ostream_iterator
transform
принимает объект функции, который принимает элементы, чей тип совпадает с типом элементов контейнера, и преобразует их во время каждой операции копирования. В данном случае мы вычисляем transform(begin(v), end(v),
ostream_iterator
[] (int i) { return i * i; });
cout << '\n';
4. Выполним еще одно преобразование. Например, из числа 3
3^2 = 9
. Следующая функция int_to_string
делает именно это с помощью объекта std::stringstream
: auto int_to_string ([](int i) {
stringstream ss;
ss << i << "^2 = " << i * i;
return ss.str();
});
5. Функция, которую мы только что реализовали, возвращает строковые значения на основе числовых. Мы также могли бы сказать, что она
vector
transform(begin(v), end(v), back_inserter(vs),
int_to_string);
6. Выведем полученный результат на экран, и пример закончится: