Namespaces
Variants

std::ranges:: unique

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Permutation operations
Fold operations
Operations on uninitialized storage
Return types
Definido en el encabezado <algorithm>
Firma de llamada
template < std:: permutable I, std:: sentinel_for < I > S, class Proj = std:: identity ,

std:: indirect_equivalence_relation < std :: projected < I, Proj >>
C = ranges:: equal_to >
constexpr ranges:: subrange < I >

unique ( I first, S last, C comp = { } , Proj proj = { } ) ;
(1) (desde C++20)
template < ranges:: forward_range R, class Proj = std:: identity ,

std:: indirect_equivalence_relation < std :: projected < ranges:: iterator_t < R > , Proj >>
C = ranges:: equal_to >
requires std:: permutable < ranges:: iterator_t < R >>
constexpr ranges:: borrowed_subrange_t < R >

unique ( R && r, C comp = { } , Proj proj = { } ) ;
(2) (desde C++20)
1) Elimina todos excepto el primer elemento de cada grupo consecutivo de elementos equivalentes del rango [ first , last ) y devuelve un subrango [ ret , last ) , donde ret es un iterador más allá del final para el nuevo final del rango.
Dos elementos consecutivos *(i - 1) y *i se consideran equivalentes si std:: invoke ( comp, std:: invoke ( proj, * ( i - 1 ) ) , std:: invoke ( proj, * i ) ) == true , donde i es un iterador en el rango [ first + 1 , last ) .
2) Igual que (1) , pero utiliza r como el rango, como si usara ranges:: begin ( r ) como first , y ranges:: end ( r ) como last .

Las entidades similares a funciones descritas en esta página son algorithm function objects (conocidas informalmente como niebloids ), es decir:

Contenidos

Parámetros

first, last - el par iterador-centinela que define el rango de elementos a procesar
r - el rango de elementos a procesar
comp - el predicado binario para comparar los elementos proyectados
proj - la proyección a aplicar a los elementos

Valor de retorno

Devuelve { ret, last } , donde ret es un iterador que apunta después del final para el nuevo final del rango.

Complejidad

Para rangos no vacíos, exactamente ranges:: distance ( first, last ) - 1 aplicaciones del predicado correspondiente comp y no más del doble de aplicaciones de cualquier proyección proj .

Notas

La eliminación se realiza desplazando (mediante asignación de movimiento) los elementos en el rango de tal manera que los elementos que no se deben eliminar aparecen al principio del rango. El orden relativo de los elementos que permanecen se conserva y el tamaño físico del contenedor no cambia. Los iteradores en [ ret , last ) (si los hay) siguen siendo desreferenciables, pero los elementos mismos tienen valores no especificados (según la MoveAssignable postcondición).

Una llamada a ranges::unique a veces es seguida por una llamada a la función miembro erase del contenedor, que borra los valores no especificados y reduce el tamaño físico del contenedor para que coincida con su nuevo tamaño lógico . Estas dos invocaciones juntas modelan el Erase–remove idiom .

Implementación posible

struct unique_fn
{
    template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity,
             std::indirect_equivalence_relation<std::projected<I, Proj>>
                 C = ranges::equal_to>
    constexpr ranges::subrange<I>
        operator()(I first, S last, C comp = {}, Proj proj = {}) const
    {
        first = ranges::adjacent_find(first, last, comp, proj);
        if (first == last)
            return {first, first};
        auto i {first};
        ++first;
        while (++first != last)
            if (!std::invoke(comp, std::invoke(proj, *i), std::invoke(proj, *first)))
                *++i = ranges::iter_move(first);
        return {++i, first};
    }
    template<ranges::forward_range R, class Proj = std::identity,
             std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>, Proj>>
                 C = ranges::equal_to>
    requires std::permutable<ranges::iterator_t<R>>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, C comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r),
                       std::move(comp), std::move(proj));
    }
};
inline constexpr unique_fn unique {};

Ejemplo

#include <algorithm>
#include <cmath>
#include <complex>
#include <iostream>
#include <vector>
struct id {
    int i;
    explicit id(int i) : i {i} {}
};
void print(id i, const auto& v)
{
    std::cout << i.i << ") ";
    std::ranges::for_each(v, [](auto const& e) { std::cout << e << ' '; });
    std::cout << '\n';
}
int main()
{
    // un vector que contiene varios elementos duplicados
    std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
    print(id {1}, v);
    // eliminar duplicados consecutivos (adyacentes)
    const auto ret = std::ranges::unique(v);
    // v ahora contiene {1 2 1 3 4 5 4 x x x}, donde 'x' es indeterminado
    v.erase(ret.begin(), ret.end());
    print(id {2}, v);
    // ordenar seguido de unique, para eliminar todos los duplicados
    std::ranges::sort(v); // {1 1 2 3 4 4 5}
    print(id {3}, v);
    const auto [first, last] = std::ranges::unique(v.begin(), v.end());
    // v ahora contiene {1 2 3 4 5 x x}, donde 'x' es indeterminado
    v.erase(first, last);
    print(id {4}, v);
    // unique con comparación y proyección personalizadas
    std::vector<std::complex<int>> vc { {1, 1}, {-1, 2}, {-2, 3}, {2, 4}, {-3, 5} };
    print(id {5}, vc);
    const auto ret2 = std::ranges::unique(vc,
        // considerar dos números complejos iguales si sus partes reales son iguales en módulo:
        [](int x, int y) { return std::abs(x) == std::abs(y); }, // comp
        [](std::complex<int> z) { return z.real(); }             // proj
    );
    vc.erase(ret2.begin(), ret2.end());
    print(id {6}, vc);
}

Salida:

1) 1 2 1 1 3 3 3 4 5 4
2) 1 2 1 3 4 5 4
3) 1 1 2 3 4 4 5
4) 1 2 3 4 5
5) (1,1) (-1,2) (-2,3) (2,4) (-3,5)
6) (1,1) (-2,3) (-3,5)

Véase también

crea una copia de un rango de elementos que no contiene duplicados consecutivos
(objeto función de algoritmo)
encuentra los dos primeros elementos adyacentes que son iguales (o satisfacen un predicado dado)
(objeto función de algoritmo)
elimina elementos que cumplen criterios específicos
(objeto función de algoritmo)
elimina elementos duplicados consecutivos en un rango
(plantilla de función)
elimina elementos duplicados consecutivos
(función miembro pública de std::list<T,Allocator> )
elimina elementos duplicados consecutivos
(función miembro pública de std::forward_list<T,Allocator> )