Namespaces
Variants

std::ranges::unique

De es.cppreference.net
 
 
Biblioteca de algoritmos
Algoritmos restringidos y algoritmos sobre rangos (C++20)
Algoritmos restringidos, p. ej. ranges::copy, ranges::sort, ...
Operaciones de secuencia no modificadoras    
Operaciones por lotes
(C++17)
Operaciones de búsqueda
Operaciones de secuencia modificadoras
Operaciones de copia
(C++11)
(C++11)
Operaciones de intercambio
Operaciones de transformación
Operaciones de generación
Operaciones de eliminación
Operaciones de cambio de orden
(hasta C++17)(C++11)
(C++20)(C++20)
Operaciones de muestreo
(C++17)

Ordenación y operaciones relacionadas
Operaciones de particionado
(C++11)    

Operaciones de ordenación
Operaciones de búsqueda binaria
(en rangos particionados)
Operaciones de conjunto (en rangos ordenados)
Operaciones de mezcla (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
(C++11)
(C++17)
Operaciones de comparación lexicográfica
Operaciones de permutación


 
Algoritmos restringidos
Todos los nombres en este menú pertenecen al espacio de nombres std::ranges
Operaciones de secuencia no modificadoras
Operaciones de secuencia modificadoras
Operaciones de particionado
Operaciones de ordenación
Operaciones de búsqueda binaria (en rangos ordenados)
       
       
Operaciones de conjunto (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
       
       
Operaciones de permutación
Operaciones de plegado
Operaciones sobre almacenamiento no inicializado
Tipos de retorno
 
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 pasado el 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 usa r como el rango, como si se usara ranges::begin(r) como first, y ranges::end(r) como last.

Las entidades similares a funciones descritas en esta página son objetos de función de algoritmo (conocidos informalmente como niebloides), es decir:

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