Модифікуючі алгоритми. Частина 1.
Алгоритми, які змінюють значення елементів послідовності
Зміст
- 1. Алгоритм for_each. Виконати операцію над кожним елементом послідовності
- 2. Алгоритм transform. Виконати дію для кожного елементу послідовності
- 3. Алгоритм fill. Заповнити діапазон потрібними значеннями
- 4. Алгоритм fill_n. Заповнити діапазон потрібними значеннями
- 5. Алгоритм generate. Виконати операцію над кожним елементом послідовності
- 6. Алгоритм generate_n. Виконати операцію над кожним елементом послідовності
- Споріднені теми
Пошук на інших ресурсах:
1. Алгоритм for_each. Виконати операцію над кожним елементом послідовності
Алгоритм for_each дозволяє виконувати задану операцію над кожним елементом послідовності. Ця операція задається функцією. Загальна форма поширеної реалізації алгоритму виглядає наступним чином
template <class InputIterator, class Function> Function for_each( InputIterator first, InputIterator last, Function func);
тут
- first – ітератор вводу, що вказує на перший елемент діапазону, над яким потрібно виконати операцію;
- last – ітератор вводу, що вказує на останній елемент діапазону, над яким потрібно виконати операцію;
- func – функція, що визначає операцію.
Приклад 1.
У прикладі кожен елемент вектору множиться на 2. Для множення використовується функція Mult2().
#include <iostream> #include <vector> #include <queue> #include <list> #include <algorithm> #include <functional> using namespace std; void Mult2(int& value) { value = value * 2; } void main() { // Алгоритм for_each. Виконати операцію над кожним елементом послідовності // 1. Створити динамічний масив vector<int> V = { 4, 8, 9, 2, 10, 15 }; // 2. Викликати алгоритм for_each // Тут використовується функція Mult2() for_each(V.begin(), V.end(), Mult2); // кожен елемент вектору множиться на 2 // 3. Вивести результуючий масив vector<int>::iterator p1; p1 = V.begin(); while (p1 != V.end()) { cout << *p1 << " "; p1++; } cout << endl; }
Приклад 2.
У прикладі кожен рядок списку list<string> реверсується з допомогою алгоритму for_each. Функція реверсування Reverse().
#include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; // Функція, яка реверсує рядок void Reverse(string& s) { string s2 = ""; for (int i = 0; i < s.length(); i++) { s2 = s[i] + s2; } s.assign(s2); } void main() { // Алгоритм for_each. Виконати операцію над кожним елементом послідовності // 1. Створити список рядків list<string> L = { "abc", "def", "ghi", "jkl" }; // 2. Викликати алгоритм for_each // Тут використовується функція Mult2() for_each(L.begin(), L.end(), Reverse); // кожен елемент списку реверсується // 3. Вивести результуючий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Результат
cba fed ihg lkj
⇑
2. Алгоритм transform. Виконати дію для кожного елементу послідовності
Алгоритм transform дозволяє задати операцію, яка буде виконуватись над кожним елементом послідовності або над парою елементів у двох вихідних діапазонах. Операція може бути задана унарною або бінарною функцією. Оголошення найбільш поширених реалізацій алгоритму має вигляд
template <class InputIterator, class OutputIterator, class UnaryFunction> OutputIterator transform( InputIterator first1, InputIterator last1, OutputIterator result, UnaryFunction func ); template <class InputIterator1, class InputIterator2, class OutputIterator, class BinaryFunction> OutputIterator transform( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryFunction func );
тут
- first1, last1 – ітератори вводу, що задають перший вихідний діапазон для обробки;
- first2 – ітератор вводу, що задає другий діапазон для обробки;
- result – ітератор виводу, що вказує на позицію першого елементу в діапазоні призначення;
- func – унарна або бінарна функція, що задає операцію яку потрібно виконати над одним елементом або над декількома елементами.
Приклад.
#include <iostream> #include <list> #include <algorithm> using namespace std; // Предикат, що виконує операцію над окремим елементом послідовності, // помножити значення параметру value на 5 int Mult_5(int value) { return value * 5; } // Предикат, що виконує операцію над двома окремими елементами. // Ці елементи можуть бути з різних послідовностей. int Mult_AB(int a, int b) { return a * b; // повернути добуток елементів } int main() { // Алгоритм transform - виконати функцію для кожного елементу цієї послідовності // 1. Використання алгоритму в поєднанні з предикатом // 1.1. Створити послідовність чисел та вивести її на консоль list<int> L1 = { 2, 8, 1, 4, 3, 5, 7, 0, -2, 6, 3 }; cout << "L1 => "; for (int i : L1) cout << i << " "; cout << endl; // 1.2. Створити іншу послідовніть розміром вихідної list<int> L2(L1.size()); // 1.3. Викликати алгоритм transform для списку L1 на основі предикату Mult_5, // утворюється нова послідовність L2 transform(L1.begin(), L1.end(), L2.begin(), Mult_5); // 1.4. Вивести результуючу послідовність L2 cout << "L2 => "; for (int i : L2) cout << i << " "; cout << endl; // 2. Використання алгоритму на основі лямбда-виразу // 2.1. Утворити послідовність L3 нульових значень розміром L1.size() list<int> L3(L1.size()); // 2.2. Створити другу послідовність, кожен елемент якої // є помноженим на 2 - викликати алгоритм transform transform(L1.begin(), L1.end(), L3.begin(), [](int a) { return a * 2; }); // 2.3. Вивести результуючу послідовність cout << "L3 => "; for (int i : L3) cout << i << " "; cout << endl; // 3. Використання алгоритму transform для виконання операції над двома послідовностями. // Потрібно помножити елементи послідовності L1 на елементи послідовності L2 // 3.1. Створити нову послідовність розміром L1.size() list<int> L4(L1.size()); // 3.2. Заповнити послідовність L4 значеннями L1[i]*L2[i] transform(L1.begin(), L1.end(), L2.begin(), L4.begin(), Mult_AB); // 3.3. Вивести послідовність L4 cout << "L1[i]*L2[i] => "; for (int i : L4) cout << i << " "; cout << endl; // 4. Використання алгоритму transform для виконання операції над двома послідовностями // на основі лямбда-виразу. // Отримати нову послідовність, в якій поелементно додаються послідовності L1 та L2. // 4.1. Створити нову нульову послідовність L5 розміром L1.size(). list<int> L5(L1.size()); // 4.2. Заповнити послідовність L5 значеннями L1[i]+L2[i] на основі лямбда-виразу. transform( L1.begin(), // початок L1 L1.end(), // кінець L1, L1.end()-L1.begin() => це є довжина результуючої послідовності L2.begin(), // початок другої послідовності, яка додається до L1 L5.begin(), // початок результуючої послідовності [](int a, int b) { return a + b; } // лямбда-вираз, що повертає суму параметрів a та b ); // 4.3. Вивести результуючу послідовність cout << "L1[i]+L2[i] => "; for (int i : L5) cout << i << " "; cout << endl; }
Результат
L1 => 2 8 1 4 3 5 7 0 -2 6 3 L2 => 10 40 5 20 15 25 35 0 -10 30 15 L3 => 4 16 2 8 6 10 14 0 -4 12 6 L1[i]*L2[i] => 20 320 5 80 45 125 245 0 20 180 45 L1[i]+L2[i] => 12 48 6 24 18 30 42 0 -12 36 18
⇑
3. Алгоритм fill. Заповнити діапазон потрібними значеннями
Алгоритм fill призначений для присвоєння кожному елементу в заданому діапазоні деякого значення. Оголошення алгоритму має вигляд
template <class ForwardIterator, class Type> void fill( ForwardIterator first, ForwardIterator last, const Type& value);
тут
- first, last – прямі ітератори, що використовуються для задавання діапазону;
- value – значення, яким заповнюється діапазон.
Приклад.
#include <iostream> #include <queue> #include <vector> #include <list> #include <functional> #include <algorithm> using namespace std; int main() { // Алгоритм fill - заповнити діапазон потрібними значеннями // 1. Оголосити вектор з 5 елементів vector<int> V(5); // 2. Заповнити вектор значенням 10 fill(V.begin(), V.end(), 10); // 3. Вивести вектор на екран cout << "V => "; for (int i : V) cout << i << " "; cout << endl; // 4. Оголосити список з 10 елементів list<double> L(10); // 5. Заповнити список значенням 5.0 fill(L.begin(), L.end(), 5.0); // 6. Вивести список на екран cout << "L => "; for (double d : L) cout << d << " "; cout << endl; }
Результат
V => 10 10 10 10 10 L => 5 5 5 5 5 5 5 5 5 5
⇑
4. Алгоритм fill_n. Заповнити діапазон потрібними значеннями
Алгоритм fill_n присвоює нове значення вказаній кількості елементів в діапазоні, починаючи з визначеного елементу.
Поширена реалізація алгоритму наступна
template <class OutputIterator, class Size, class Type> OutputIterator fill_n( OutputIterator first, Size count, const Type& value);
тут
- first – ітератор, що вказує на початок діапазону;
- count – кількість елементів, які присвоюються;
- value – значення, що присвоюється елементам діапазону.
Приклад.
#include <iostream> #include <queue> #include <vector> #include <list> #include <functional> #include <algorithm> using namespace std; int main() { // Алгоритм fill - заповнити діапазон потрібними значеннями // 1. Оголосити вектор з 5 елементів vector<int> V(5); // 2. Заповнити перші 3 елементи вектору значенням 10 fill_n(V.begin(), 3, 10); // 3. Вивести вектор на екран cout << "V => "; for (int i : V) cout << i << " "; cout << endl; // 4. Оголосити список з 10 елементів list<double> L(10); // 5. Заповнити перші 7 елементів списку значенням 1.0 fill_n(L.begin(), 7, 1.0); // 6. Вивести список на екран cout << "L => "; for (double d : L) cout << d << " "; cout << endl; }
Результат
V => 10 10 10 0 0 L => 1 1 1 1 1 1 1 0 0 0
⇑
5. Алгоритм generate. Виконати операцію над кожним елементом послідовності
Алгоритм generate присвоює значення, що створюються об’єктом функції, кожному елементу в діапазоні. Загальна форма алгоритму наступна
template <class ForwardIterator, class Generator> void generate( ForwardIterator first, ForwardIterator last, Generator gen);
тут
- first, last – ітератори, що визначають діапазон значень, які обробляються;
- gen – об’єкт функції, що викликається без аргументів для створення значень, присвоєних кожному елементу в діапазоні.
Приклад 1.
У прикладі з допомогою лямбда-виразу записується значення “abcd” у кожен рядок списку L.
#include <list> #include <algorithm> #include <functional> using namespace std; void main() { // Алгоритм generate. Виконати операцію над кожним елементом послідовності // 1. Створити список рядків list<string> L = { "abc", "def", "ghi", "jkl" }; // 2. Викликати алгоритм generate // Записати "abcd" у кожен елемент списку з допомогою лямбда-виразу generate(L.begin(), L.end(), []() { return "abcd"; }); // 3. Вивести результуючий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Приклад 2.
У прикладі генерується масив чисел 5.0 шляхом виклику функції Get5().
#include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std; // Функція, яка повертає число 5 double Get5() { return 5.0; } void main() { // Алгоритм generate. Виконати операцію над кожним елементом послідовності // 1. Створити масив з 10 чисел vector<double> V(10); // 2. Викликати алгоритм generate // Записати число у кожен елемент масиву з допомогою функції Get5() generate(V.begin(), V.end(), Get5); // 4. Вивести результуючий масив vector<double>::iterator it; it = V.begin(); while (it != V.end()) { cout << *it << " "; it++; } cout << endl; }
Результат
5 5 5 5 5 5 5 5 5 5
⇑
6. Алгоритм generate_n. Виконати операцію над кожним елементом послідовності
Алгоритм generate_n присвоює значення заданій кількості елементів послідовності, які були створені об’єктом функції. Алгоритм повертає позицію за останнім присвоєним значенням
template <class OutputIterator, class Diff, class Generator> void generate_n( OutputIterator first, Diff count, Generator gen);
тут
- first – ітератор, який вказує на початок діапазону;
- count – кількість елементів, яким присвоюється значення;
- gen – об’єкт функції без аргументів, який використовується для формування значень.
Приклад 1.
#include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; void main() { // Алгоритм generate_n. Виконати операцію над кожним елементом послідовності // 1. Створити список рядків list<string> L; // 2. Створити 5 пустих рядків L.resize(5, ""); // 3. Викликати алгоритм generate_n // Записати "abcd" у кожен елемент списку з допомогою лямбда-виразу generate_n(L.begin(), L.size(), []() { return "abcd"; }); // 4. Вивести результуючий список list<string>::iterator it; it = L.begin(); while (it != L.end()) { cout << *it << endl; it++; } cout << endl; }
Приклад 2.
У прикладі формується масив випадкових чисел, значення яких лежать в діапазоні [1; 10].
#include <iostream> #include <vector> #include <algorithm> #include <functional> #include <time.h> using namespace std; // Функція, яка повертає випадкове число // в межах від 1 до 10 включно int Get_1_10() { int value = rand() % 10 + 1; return value; } void main() { // Алгоритм generate_n. Виконати операцію над кожним елементом послідовності // 1. Створити масив з 10 чисел vector<int> V(10); // 2. Ініціалізувати ядро для отримання випадкових значень srand(time(NULL)); // 2. Викликати алгоритм generate_n // Записати число у кожен елемент масиву з допомогою функції Get_1_10() generate_n(V.begin(), V.size(), Get_1_10); // 4. Вивести результуючий масив vector<int>::iterator it; it = V.begin(); while (it != V.end()) { cout << *it << " "; it++; } cout << endl; }
⇑
Споріднені теми
- Модифікуючі алгоритми. Частина 2. Алгоритми обміну значеннями елементів послідовності. Алгоритми swap, swap_ranges, iter_swap
- Модифікуючі алгоритми. Частина 3. Алгоритми, що виконують заміну елементів послідовності. Алгоритми replace, replace_if, replace_copy_if, replace_copy
- Модифікуючі алгоритми. Частина 4. Алгоритми, що витягують з послідовності окремі елементи або групи елементів: remove, remove_if, remove_copy, remove_copy_if, unique, unique_copy
- Модифікуючі алгоритми. Частина 5. Алгоритми, що обробляють послідовність в цілому не змінюючи значень елементів: copy, copy_backward, reverse, reverse_copy, rotate, rotate_copy, random_shuffle
⇑