std::ranges::unique
| 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) |
[first, last) y devuelve un subrango [ret, last), donde ret es un iterador pasado el final para el nuevo final del rango.*(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).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:
- No se pueden especificar listas explícitas de argumentos de plantilla al llamar a cualquiera de ellos.
- Ninguno de ellos es visible para la búsqueda dependiente de argumentos.
- Cuando cualquiera de ellos se encuentra mediante búsqueda normal no calificada como el nombre a la izquierda del operador de llamada a función, la búsqueda dependiente de argumentos se inhibe.
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
|
(C++20)
|
crea una copia de un rango de elementos que no contiene duplicados consecutivos
(objeto función de algoritmo) |
|
(C++20)
|
encuentra los dos primeros elementos adyacentes que son iguales (o satisfacen un predicado dado)
(objeto función de algoritmo) |
|
(C++20)
(C++20)
|
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>
)
|