C++. STL. Algorithms. Algorithms that change all elements of a sequence

Modifying algorithms. Part 1.
Algorithms that change all elements of a sequence


Contents


Search other resources:

1. Algorithm for_each. Perform an operation on each element of the sequence.

The for_each algorithm allows you to perform a given operation on each element of a sequence. This operation is specified by a function. The general form of a common implementation of the algorithm is as follows

template <class InputIterator, class Function>
Function for_each(
  InputIterator first,
  InputIterator last,
  Function func);

where

  • first – input iterator pointing to the first element of the range to be operated on;
  • last – input iterator pointing to the last element of the range on which the operation is to be performed;
  • func – function that defines the operation.

Example 1.

In the example, each element of the vector is multiplied by 2. For multiplication, the Mult2() function is used.

#include <iostream>
#include <vector>
#include <queue>
#include <list>
#include <algorithm>
#include <functional>
using namespace std;

void Mult2(int& value)
{
  value = value * 2;
}

void main()
{
  // Algorithm for_each. Perform an operation on each element of a sequence
  // 1. Create dynamic array
  vector<int> V = { 4, 8, 9, 2, 10, 15 };

  // 2. Call the for_each algorithm
  // Here the Mult2() function is used
  for_each(V.begin(), V.end(), Mult2); // each element of the vector is multiplied by 2

  // 3. Output the resulting array
  vector<int>::iterator p1;

  p1 = V.begin();
  while (p1 != V.end())
  {
    cout << *p1 << " ";
    p1++;
  }

  cout << endl;
}

Example 2.

In our example, each line of list<string> is reversed using the for_each algorithm (Reverse() function).

#include <iostream>
#include <list>
#include <algorithm>
#include <functional>
using namespace std;

// A function that reverses a string
void Reverse(string& s)
{
  string s2 = "";
  for (int i = 0; i < s.length(); i++)
  {
    s2 = s[i] + s2;
  }
  s.assign(s2);
}

void main()
{
  // Algorithm for_each. Perform operation on each element of a sequence
  // 1. Create a list of strings
  list<string> L = {
    "abc",
    "def",
    "ghi",
    "jkl"
  };

  // 2. Call the for_each algorithm
  // The Mult2() function is used here
  for_each(L.begin(), L.end(), Reverse); // each element of the list is reversed

  // 3. Display the resulting list
  list<string>::iterator it;

  it = L.begin();
  while (it != L.end())
  {
    cout << *it << endl;
    it++;
  }

  cout << endl;
}

Result

cba
fed
ihg
lkj

 

2. Algorithm transform. Perform action for each element of a sequence

The transform algorithm allows you to specify an operation to be performed on each element of a sequence or on a pair of elements in two output ranges. The operation can be specified as a unary or binary function. The declaration of the most common implementations of the algorithm is

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 );

where

  • first1, last1 – input iterators specifying the first output range for processing;
  • first2 – input iterator specifying the second range for processing;
  • result – output iterator pointing to the position of the first element in the destination range;
  • func – unary or binary function that specifies an operation to be performed on one element or on several elements.

Example.

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

// A predicate that performs the operation on a single element of a sequence,
// multiply the value of the value parameter by 5
int Mult_5(int value)
{
  return value * 5;
}

// A predicate that performs an operation on two distinct elements.
// These elements can be from different sequences.
int Mult_AB(int a, int b)
{
  return a * b; // return the product of the elements
}

int main()
{
  // The transform algorithm – execute a function for each element of this sequence

  // 1. Using the algorithm in combination with the predicate.
  // 1.1. Create a sequence of numbers and print it to the console.
  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. Create another sequence the same size as the original one
  list<int> L2(L1.size());

  // 1.3. Call the transform algorithm for the L1 list based on the Mult_5 predicate,
  // new L2 sequence is created
  transform(L1.begin(), L1.end(), L2.begin(), Mult_5);

  // 1.4. Output the resulting sequence L2
  cout << "L2 => ";
  for (int i : L2)
    cout << i << " ";
  cout << endl;

  // 2. Using algorithm based on the lambda expression.
  // 2.1. Create a sequence of L3 zero values of size L1.size()
  list<int> L3(L1.size());

  // 2.2. Create a second sequence, each element of which
  //      is multiplied by 2 - call the transform algorithm
  transform(L1.begin(), L1.end(), L3.begin(), [](int a) { return a * 2; });

  // 2.3. Display the resulting sequence
  cout << "L3 => ";
  for (int i : L3)
    cout << i << " ";
  cout << endl;

  // 3. Using the transform algorithm to perform operation on two sequences.
  // It is necessary to multiply the elements of the sequence L1 by the elements of the sequence L2

  // 3.1. Create a new sequence of size L1.size()
  list<int> L4(L1.size());

  // 3.2. Fill the L4 sequence with values L1[i]*L2[i]
  transform(L1.begin(), L1.end(), L2.begin(), L4.begin(), Mult_AB);

  // 3.3. Print the sequence L4
  cout << "L1[i]*L2[i] => ";
  for (int i : L4)
    cout << i << " ";
  cout << endl;

  // 4. Using the transform algorithm to perform operation on two sequences based on a lambda expression.
  // Get a new sequence in which the sequences L1 and L2 are added element by element.
  // 4.1. Create a new L5 null sequence of size L1.size().
  list<int> L5(L1.size());

  // 4.2. Fill sequence L5 with values L1[i]+L2[i] based on lambda expression.
  transform(
    L1.begin(), // the begin of L1
    L1.end(),   // the end of L1, L1.end()-L1.begin() => this is the length of the resulting sequence
    L2.begin(), // the beginning of the second sequence, attached to L1
    L5.begin(), // the beginning of the resulting sequence
    [](int a, int b) { return a + b; } // lambda expression that returns the sum of a and b
  );

  // 4.3. Display the resulting sequence
  cout << "L1[i]+L2[i] => ";
  for (int i : L5)
    cout << i << " ";
  cout << endl;
}

Result

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. Algorithm fill. Fill the range with the desired values

The fill algorithm is designed to assign a value to each element in a given range. The declaration of the algorithm is

template <class ForwardIterator, class Type>
void fill(
  ForwardIterator first,
  ForwardIterator last,
  const Type& value);

here

  • first, last – direct iterators used to set the range;
  • value – value that fills the range.

Example.

#include <iostream>
#include <queue>
#include <vector>
#include <list>
#include <functional>
#include <algorithm>
using namespace std;

int main()
{
  // The fill algorithm - fill the range with the desired values

  // 1. Declaring a 5-element vector
  vector<int> V(5);

  // 2. Fill the vector with value 10
  fill(V.begin(), V.end(), 10);

  // 3. Display the vector on the screen
  cout << "V => ";
  for (int i : V)
    cout << i << " ";
  cout << endl;

  // 4. Declare a list of 10 elements
  list<double> L(10);

  // 5. Fill list with value 5.0
  fill(L.begin(), L.end(), 5.0);

  // 6. Display the list on the screen
  cout << "L => ";
  for (double d : L)
    cout << d << " ";
  cout << endl;
}

Result

V => 10 10 10 10 10
L => 5 5 5 5 5 5 5 5 5 5

 

4. Algorithm fill_n. Fill in the range with the required values.

The fill_n algorithm assigns a new value to a specified number of elements in a range, starting at a particular element.

A common implementation of the algorithm is as follows

template <class OutputIterator, class Size, class Type>
OutputIterator fill_n(
  OutputIterator first,
  Size count,
  const Type& value);

where

  • first – an iterator pointing to the beginning of the range;
  • count – number of elements to be assigned;
  • value – the value that is assigned to the elements of the range.

Example.

#include <iostream>
#include <queue>
#include <vector>
#include <list>
#include <functional>
#include <algorithm>
using namespace std;

int main()
{
  // The fill algorithm - fill the range with the desired values

  // 1. Declare a vector of 5 elements
  vector<int> V(5);

  // 2. Fill the first 3 elements of the vector with the value 10
  fill_n(V.begin(), 3, 10);

  // 3. Display the vector on the screen
  cout << "V => ";
  for (int i : V)
    cout << i << " ";
  cout << endl;

  // 4. Declare a list of 10 elements
  list<double> L(10);

  // 5. Fill the first 7 elements of the list with the value 1.0
  fill_n(L.begin(), 7, 1.0);

  // 6. Display the list on the screen
  cout << "L => ";
  for (double d : L)
    cout << d << " ";
  cout << endl;
}

Result

V => 10 10 10 0 0
L => 1 1 1 1 1 1 1 0 0 0

 

5. Algorithm generate. Perform operation on each element of a sequence

The generate algorithm assigns values to each element in the range generated by the function object. The general form of algorithm is as follows

template <class ForwardIterator, class Generator>
void generate(
  ForwardIterator first,
  ForwardIterator last,
  Generator gen);

where

  • first, last – iterators defining the range of processed values;
  • gen – object of a function called with no arguments to generate values to be assigned to each element in the range.

Example 1.

The example uses a lambda expression to write the value “abcd” in each row of the list L.

#include <list>
#include <algorithm>
#include <functional>
using namespace std;

void main()
{
  // Algorithm generate. Perform an operation on each element of the sequence
  // 1. Create a list of strings
  list<string> L = {
    "abc",
    "def",
    "ghi",
    "jkl"
  };

  // 2. Call the algorithm generate
  // Write "abcd" to each element of the list using a lambda expression.
  generate(L.begin(), L.end(), []() { return "abcd"; });

  // 3. Display the resulting string
  list<string>::iterator it;

  it = L.begin();
  while (it != L.end())
  {
    cout << *it << endl;
    it++;
  }

  cout << endl;
}

Example 2.

The example generates an array of numbers 5.0 by calling the Get5() function.

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

// A function that returns the number 5
double Get5()
{
  return 5.0;
}

void main()
{
  // Algorithm generate. Perform operation on each element of the sequence
  // 1. Create array of 10 numbers
  vector<double> V(10);

  // 2. Call algorithm generate
  // Write a number to each element of array using the Get5() function
  generate(V.begin(), V.end(), Get5);

  // 4. Display the resulting array
  vector<double>::iterator it;

  it = V.begin();
  while (it != V.end())
  {
    cout << *it << " ";
    it++;
  }

  cout << endl;
}

Result

5 5 5 5 5 5 5 5 5 5

 

6. Algorithm generate_n. Perform an operation on each element of the sequence

The generate_n algorithm assigns a value to a given number of sequence elements that were generated by the function object. The algorithm returns the position after the last value assigned

template <class OutputIterator, class Diff, class Generator>
void generate_n(
  OutputIterator first,
  Diff count,
  Generator gen);

where

  • first – iterator pointing to the beginning of the range;
  • count – the number of elements to which a value is assigned;
  • gen – function object without arguments, used to generate values.

Example 1.

#include <iostream>
#include <list>
#include <algorithm>
#include <functional>
using namespace std;

void main()
{
  // Algorithm generate_n. Perform an operation on each element of the sequence
  // 1. Create a list of strings
  list<string> L;

  // 2. Create 5 empty strings
  L.resize(5, "");

  // 3. Call the generate_n algorithm
  // Write "abcd" to each element of the list using a lambda expression
  generate_n(L.begin(), L.size(), []() { return "abcd"; });

  // 4. Display the resulting list
  list<string>::iterator it;

  it = L.begin();
  while (it != L.end())
  {
    cout << *it << endl;
    it++;
  }

  cout << endl;
}

Example 2.

In the example, an array of random numbers is formed, the value of which lies in the range [1; 10].

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <time.h>
using namespace std;

// A function that returns a random number between 1 and 10 inclusive
int Get_1_10()
{
  int value = rand() % 10 + 1;
  return value;
}

void main()
{
  // Algorithm generate_n. Perform an operation on each element of a sequence
  // 1. Create an array of 10 numbers
  vector<int> V(10);

  // 2. Initialize the kernel to get random values
  srand(time(NULL));

  // 2. Call the generate_n algorithm
  // Write a number to each array element using the Get_1_10() function
  generate_n(V.begin(), V.size(), Get_1_10);

  // 4. Display the resulting array
  vector<int>::iterator it;

  it = V.begin();
  while (it != V.end())
  {
    cout << *it << " ";
    it++;
  }

  cout << endl;
}

 


Related topics