Копирование элементов

Последнее обновление: 31.03.2023

Функция std::copy_if() применяется для копирования значений, которые соответствуют некоторому условию, из одного диапазона в другой. Эта функция имеет ряд версий, рассмотрим одну из из них:

iterator std::copy_if(start_source_iterator, end_source_iterator, start_dest_iterator, condition)

Первые два параметра - start_source_iterator и end_source_iterator представляют соответственно итераторы на начало и конец диапазона значений, откуда надо копировать значения. Третий параметр - start_dest_iterator представляет итератор на начало диапазона, в который надо вставить скопированные значения.

Последний параметр - condition представляет условие. В качестве условия выступает функция, которая принимает некоторое значение произвольного типа и возвращает значение типа bool - true, если значение соответствует условию, и false - если не соответствует.

Результатом функции является итератор, который указывает на адрес сразу после последнего скопированного элемента из исходного диапазона.

Рассмотрим применение функции:

#include <iostream>
#include <vector>
#include <algorithm>

// если число четное
bool is_even(int n){ return n % 2 == 0;}
// если число положительное
bool is_positive(int n){ return n > 0;}

// для вывода вектора на консоль
void print (const std::vector<int>& data)
{
    for(const auto& n: data)
    {
        std::cout << n << "\t";
    }
    std::cout << std::endl;
 }

int main()
{
    std::vector<int> numbers { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
    std::vector<int> even_numbers (numbers.size());
    std::vector<int> pos_numbers (numbers.size());

    auto end_even_iter = std::copy_if(begin(numbers), end(numbers), begin(even_numbers), is_even);
    even_numbers.erase(end_even_iter, end(even_numbers));
    print(even_numbers);   //   -4      -2      0       2       4

    auto end_pos_iter = std::copy_if(begin(numbers), end(numbers), begin(pos_numbers), is_positive);
    pos_numbers.erase(end_pos_iter, end(pos_numbers));
    print(pos_numbers);   //    1       2       3       4       5
}

В данном случае копируем из вектора чисел numbers в два других вектора - even_numbers и pos_numbers. Обратите внимание, что для обоих последних векторов задана длина:

std::vector<int> even_numbers (numbers.size());
std::vector<int> pos_numbers (numbers.size());

Теоретически все элементы вектора numbers могут соответствовать условию, поэтому для обоих векторов устанавливается длина, равная длине вектора numbers.

Условия заданы отдельными функциями - is_even (определяет, является ли число четное) и is_positive (является ли число положительным).

Сначала копируем из вектора numbers в вектор even_numbers все числа, которые являются четными:

auto end_even_iter = std::copy_if(begin(numbers), end(numbers), begin(even_numbers), is_even);

Тут диапазон поиска значений определяется итераторами на начало и конец вектора numbers. Вставляться скопированные элементы будут начиная с начала вектора even_numbers (begin(even_numbers)), а в качестве условия выступает функция is_even.

В реальности выполнение функции будет аналогично следующему:

auto output_iter = begin(even_numbers);
for (auto input_iter = begin(numbers); input_iter != end(numbers); ++input_iter)
{
	if (*input_iter % 2 == 0)
	{
		*output_iter++ = *input_iter;	// устанавливаем значения по итератору назначения
	}
}
// возвращаем итератор
auto end_even_iter = output_iter;

Таким образом, все четные числа из numbers будут скопированы в even_numbers. Но тут есть проблема - не все элементы исходного вектора numbers могут быть четными, а изначальный размер вектора even_numbers равен размеру numbers. Чтобы оставить в even_numbers только скопированное количество элементов, усекаем вектор even_numbers до позиции последнего скопированного элементам, на который указывает указатель end_even_iter.

even_numbers.erase(end_even_iter, end(even_numbers));

Аналогичным образом получаем положительные числа, только в качестве условия применяется функция is_positive:

auto end_pos_iter = std::copy_if(begin(numbers), end(numbers), begin(pos_numbers), is_positive);
pos_numbers.erase(end_pos_iter, end(pos_numbers));

Консольный вывод программы:

-4      -2      0       2       4
1       2       3       4       5
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850