std::ranges::remove, std::ranges::remove_if
Definido en el archivo de encabezado <algorithm>
|
||
Signatura de la llamada |
||
template< std::permutable I, std::sentinel_for<I> S, class T, class Proj = std::identity > |
(1) | (desde C++20) |
template< ranges::forward_range R, class T, class Proj = std::identity > requires std::permutable<ranges::iterator_t<R>> && |
(2) | (desde C++20) |
template< std::permutable I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred > |
(3) | (desde C++20) |
template< ranges::forward_range R, class Proj = std::identity, std::indirect_unary_predicate< |
(4) | (desde C++20) |
Elimina todos los elementos que satisfacen un criterio específico del rango [
first,
last)
y devuelve un subrango [
ret,
last)
, donde ret es un iterador pasado el final para el nuevo final del rango.
La eliminación se realiza desplazando (mediante la asignación de movimiento) los elementos del rango de forma que los elementos que no se van a eliminar aparezcan al principio del rango. Se conserva el orden relativo de los elementos que quedan y el tamaño: físico del contenedor no cambia. Los iteradores que apuntan a un elemento entre el nuevo final lógico y el final físico del rango siguen siendo desreferenciables, pero los elementos en sí tienen valores no especificados (según la poscondición de MoveAssignable).
Las entidades similares a funciones descritas en esta página son niebloids, es decir:
- Las listas de argumentos de plantilla explícitas no se pueden especificar al llamar a cualquiera de ellas.
- Ninguna de ellas es visible para la búsqueda dependiente de argumentos.
- Cuando alguna de ellas se encuentra mediante la búsqueda normal no calificada como el nombre a la izquierda del operador de llamada a función, se inhibe la búsqueda dependiente de argumentos.
En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.
Contenido |
[editar] Parámetros
first, last | - | El rango de elementos a procesar. |
r | - | El rango de elementos a procesar. |
value | - | El valor de los elementos a eliminar.. |
pred | - | El predicado para aplicar a los elementos proyectados. |
proj | - | La proyección para aplicar a los elementos. |
[editar] Valor de retorno
{ret, last}, donde [
first,
ret)
es el subrango resultante después de la eliminación, y los elementos en el subrango [
ret,
last)
están todos en un estado válido pero no especificado.
[editar] Complejidad
Exactamente N
aplicaciones del predicado correspondiente y cualquier proyección, donde N = ranges::distance(first, last), y N - 1 operaciones de movimiento en el peor de los casos.
[editar] Notas
Una llamada a ranges::remove
suele ir seguida de una llamada a la función miembro erase
de un 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 constituyen el llamado modismo Erase–remove, que se puede lograr mediante la función libre std::erase que tiene sobrecargas para todos los contenedores estándar de secuencia, o std::erase_if que tiene sobrecargas para todos los contenedores estándar}}.
Las funciones miembro de contenedor de nombre similar, list::remove, list::remove_if, forward_list::remove, y forward_list::remove_if borran los elementos eliminados.
Estos algoritmos no se pueden usar con contenedores asociativos como std::set y std::map porque sus tipos iterador no eliminan la referencia a los tipos MoveAssignable (las claves en estos contenedores no son modificables).
Debido a que std::remove
toma value por referencia, puede tener un comportamiento inesperado si es una referencia a un elemento del rango [
first,
last)
.
[editar] Posible implementación
remove |
---|
struct remove_fn { template<std::permutable I, std::sentinel_for<I> S, class T, class Proj = std::identity> requires std::indirect_binary_predicate< ranges::equal_to, std::projected<I, Proj>, const T*> constexpr ranges::subrange<I> operator()(I first, S last, const T& value, Proj proj = {}) const { first = ranges::find(std::move(first), last, value, proj); if (first != last) { for (I i {std::next(first)}; i != last; ++i) { if (value != std::invoke(proj, *i)) { *first = ranges::iter_move(i); ++first; } } } return {first, last}; } template<ranges::forward_range R, class T, class Proj = std::identity> requires std::permutable<ranges::iterator_t<R>> && std::indirect_binary_predicate< ranges::equal_to, std::projected< ranges::iterator_t<R>, Proj>, const T*> constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, const T& value, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), value, std::move(proj)); } }; inline constexpr remove_fn remove {}; |
remove_if |
struct remove_if_fn { template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred> constexpr ranges::subrange<I> operator()(I first, S last, Pred pred, Proj proj = {}) const { first = ranges::find_if(std::move(first), last, pred, proj); if (first != last) { for (I i {std::next(first)}; i != last; ++i) { if (!std::invoke(pred, std::invoke(proj, *i))) { *first = ranges::iter_move(i); ++first; } } } return {first, last}; } template<ranges::forward_range R, class Proj = std::identity, std::indirect_unary_predicate< std::projected<ranges::iterator_t<R>, Proj>> Pred> requires std::permutable<ranges::iterator_t<R>> constexpr ranges::borrowed_subrange_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), pred, std::move(proj)); } }; inline constexpr remove_if_fn remove_if {}; |
[editar] Ejemplo
#include <algorithm> #include <cctype> #include <iomanip> #include <iostream> #include <string> #include <string_view> int main() { std::string v1 {"No - se requiere - diagnóstico"}; std::cout << std::quoted(v1) << " (v1, tamaño: " << v1.size() << ")\n"; const auto ret = std::ranges::remove(v1, ' '); std::cout << std::quoted(v1) << " (v1 después de `remove`, tamaño: " << v1.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v1.begin(), ret.begin()), '^') << '\n'; v1.erase(ret.begin(), ret.end()); std::cout << std::quoted(v1) << " (v1 después de `erase`, tamaño: " << v1.size() << ")\n\n"; // remove_if con predicado unario personalizado: auto rm = [](char c) { return !std::isupper(c); }; std::string v2 {"Falla En La Sustitución No Es Un Error"}; std::cout << std::quoted(v2) << " (v2, tamaño: " << v2.size() << ")\n"; const auto [first, last] = std::ranges::remove_if(v2, rm); std::cout << std::quoted(v2) << " (v2 después de `remove_if`, tamaño: " << v2.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v2.begin(), first), '^') << '\n'; v2.erase(first, last); std::cout << std::quoted(v2) << " (v2 después de `erase`, tamaño: " << v2.size() << ")\n\n"; // se crea una vista sobre cadena dentro de un contenedor que se modifica por `remove_if`: for (std::string s : {"Optimización de Objeto Pequeño", "Parámetro de Plantilla de No Tipo"}) std::cout << std::quoted(s) << " => " << std::string_view {begin(s), std::ranges::remove_if(s, rm).begin()} << '\n'; }
Posible salida:
"No - se requiere - diagnóstico" (v1, tamaño: 31) "No-serequiere-diagnósticostico" (v1 después de `remove`, tamaño: 31) ^^^^^^^^^^^^^^^^^^^^^^^^^^ "No-serequiere-diagnóstico" (v1 después de `erase`, tamaño: 26) "Falla En La Sustitución No Es Un Error" (v2, tamaño: 39) "FELSNEUE La Sustitución No Es Un Error" (v2 después de `remove_if`, tamaño: 39) ^^^^^^^^ "FELSNEUE" (v2 después de `erase`, tamaño: 8) "Optimización de Objeto Pequeño" => OOP "Parámetro de Plantilla de No Tipo" => PPNT
[editar] Véase también
(C++20)(C++20) |
Copia un rango de elementos, omitiendo aquellos que satisfacen un criterio específico (niebloid) |
(C++20) |
Elimina elementos duplicados consecutivos en un rango. (niebloid) |
Elimina elementos que satisfacen un criterio específico. (plantilla de función) |