Daily bit(e) C++. std::unique, std::unique_copy

Добавлено 10 апреля 2026 в 13:40

Daily bit(e) C++ 25. Два алгоритма, один из которых удаляет повторяющиеся значения (std::unique), а другой отфильтровывает уникальные значения (std::unique_copy).

Daily bit(e) C++

Алгоритм std::unique обычно используется для отсортированного диапазона, чтобы получить список уникальных значений.

Однако этот алгоритм более прост. Он может работать с любым диапазоном, по которому возможно прямое перемещение, и он удаляет последовательные повторяющиеся значения (путем сдвига элементов в диапазоне влево). Применение std::unique к отсортированному диапазону дает в результате диапазон уникальных значений, поскольку все дубликаты являются последовательными.

Вариант с копированием std::unique_copy будет выводить уникальные значения через предоставленный выходной итератор.

Оба алгоритма предоставляют параллельный вариант в C++17 и вариант для диапазонов в C++20.

#include <vector>
#include <algorithm>
#include <ranges>
#include <iterator>

std::vector<int> data{1, 2, 2, 3, 2, 3, 3, 1, 1, 1};

// Удаляет дубликаты, сдвигая элементы
// возвращает итератор на новый конец
auto it = std::unique(data.begin(), data.end());
auto uniq = std::ranges::subrange(data.begin(), it);
// data == {1, 2, 3, 2, 3, 1, ?, ?, ?, ?}
// uniq == {1, 2, 3, 2, 3, 1}

// Чтобы действительно удалить элементы,
// мы должны вызвать erase()
data.erase(it, data.end());
// data == {1, 2, 3, 2, 3, 1}


data = {1, -2, 2, 3, -2, 3, -3, 1, -1, 1};
std::vector<int> out;

// Вариант с копированием выдает уникальные элементы
// через предоставленный итератор
std::unique_copy(data.begin(), data.end(), std::back_inserter(out),
    // Оба алгоритма поддерживают пользовательскую функцию сравнения
    [](int l, int r) {
        return std::abs(l) == std::abs(r);
    });
// out == {1, -2, 3, -2, 3, 1}

out.clear();
// Помните, что проекция в диапазонах версии C++20
// применяется только компаратору и не влияет
// на записываемые/копируемые значения
std::ranges::unique_copy(data, std::back_inserter(out),
    std::equal_to<>{},
    [](int l) { return std::abs(l); });
// out == {1, -2, 3, -2, 3, 1}

Пример на Compiler Explorer

Теги

C++ / CppSTL / Standard Template Library / Стандартная библиотека шаблоновПрограммирование