Namespaces
Variants

std::ranges:: equal_range

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
(1)
template < std:: forward_iterator I, std:: sentinel_for < I > S,

class T, class Proj = std:: identity ,
std:: indirect_strict_weak_order
< const T * , std :: projected < I, Proj >> Comp = ranges:: less >
constexpr ranges:: subrange < I > equal_range ( I first, S last, const T & value,

Comp comp = { } , Proj proj = { } ) ;
(desde C++20)
(hasta C++26)
template < std:: forward_iterator I, std:: sentinel_for < I > S,

class Proj = std:: identity ,
class T = std :: projected_value_t < I, Proj > ,
std:: indirect_strict_weak_order
< const T * , std :: projected < I, Proj >> Comp = ranges:: less >
constexpr ranges:: subrange < I > equal_range ( I first, S last, const T & value,

Comp comp = { } , Proj proj = { } ) ;
(desde C++26)
(2)
template < ranges:: forward_range R,

class T, class Proj = std:: identity ,
std:: indirect_strict_weak_order
< const T * , std :: projected < ranges:: iterator_t < R > ,
Proj >> Comp = ranges:: less >
constexpr ranges:: borrowed_subrange_t < R >

equal_range ( R && r, const T & value, Comp comp = { } , Proj proj = { } ) ;
(desde C++20)
(hasta C++26)
template < ranges:: forward_range R,

class Proj = std:: identity ,
class T = std :: projected_value_t < ranges:: iterator_t < R > , Proj > ,
std:: indirect_strict_weak_order
< const T * , std :: projected < ranges:: iterator_t < R > ,
Proj >> Comp = ranges:: less >
constexpr ranges:: borrowed_subrange_t < R >

equal_range ( R && r, const T & value, Comp comp = { } , Proj proj = { } ) ;
(desde C++26)
1) Devuelve una vista que contiene todos los elementos equivalentes a value en el rango [ first , last ) .

El rango [ first , last ) debe estar al menos parcialmente ordenado con respecto a value , es decir, debe satisfacer todos los siguientes requisitos:

  • particionado con respecto a element < value o comp ( element, value ) (es decir, todos los elementos para los cuales la expresión es true preceden a todos los elementos para los cuales la expresión es false ).
  • particionado con respecto a ! ( value < element ) o ! comp ( value, element ) .
  • para todos los elementos, si element < value o comp ( element, value ) es true entonces ! ( value < element ) o ! comp ( value, element ) también es true .

Un rango completamente ordenado cumple estos criterios.

La vista retornada se construye a partir de dos iteradores, uno apuntando al primer elemento que no es menor que value y otro apuntando al primer elemento mayor que value . El primer iterador puede obtenerse alternativamente con std::ranges::lower_bound() , el segundo - con std::ranges::upper_bound() .

2) Igual que (1) , pero utiliza r como el rango fuente, como si se usara el rango 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 examinar
r - el rango de los elementos a examinar
value - valor con el que comparar los elementos
comp - si el primer argumento es menor que (es decir, está ordenado antes) el segundo
proj - proyección a aplicar a los elementos

Valor de retorno

std::ranges::subrange que contiene un par de iteradores que definen el rango deseado, el primero apuntando al primer elemento que no es menor que value y el segundo apuntando al primer elemento mayor que value .

Si no hay elementos no menores que value , se devuelve el último iterador (iterador que es igual a last o ranges:: end ( r ) ) como primer elemento. De manera similar, si no hay elementos mayores que value , se devuelve el último iterador como segundo elemento.

Complejidad

El número de comparaciones realizadas es logarítmico en la distancia entre first y last (como máximo 2 * log 2 (last - first) + O(1) comparaciones). Sin embargo, para un iterador que no modela random_access_iterator , el número de incrementos del iterador es lineal.

Implementación posible

struct equal_range_fn
{
    template<std::forward_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity, class T = std::projected_value_t<I, Proj>,
             std::indirect_strict_weak_order
                 <const T*, std::projected<I, Proj>> Comp = ranges::less>
    constexpr ranges::subrange<I>
        operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return ranges::subrange
        (
            ranges::lower_bound(first, last, value, std::ref(comp), std::ref(proj)),
            ranges::upper_bound(first, last, value, std::ref(comp), std::ref(proj))
        );
    }
    template<ranges::forward_range R, class Proj = std::identity,
             class T = std::projected_value_t<ranges::iterator_t<R>, Proj>,
             std::indirect_strict_weak_order
                 <const T*, std::projected<ranges::iterator_t<R>,
                                           Proj>> Comp = ranges::less>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r), value,
                       std::ref(comp), std::ref(proj));
    }
};
inline constexpr equal_range_fn equal_range;

Notas

Macro de prueba de características Valor Std Característica
__cpp_lib_algorithm_default_value_type 202403 (C++26) Inicialización de lista para algoritmos ( 1,2 )

Ejemplo

#include <algorithm>
#include <compare>
#include <complex>
#include <iostream>
#include <vector>
struct S
{
    int number {};
    char name {};
    // nota: name es ignorado por estos operadores de comparación
    friend bool operator== (const S s1, const S s2) { return s1.number == s2.number; }
    friend auto operator<=>(const S s1, const S s2) { return s1.number <=> s2.number; }
    friend std::ostream& operator<<(std::ostream& os, S o)
    {
        return os << '{' << o.number << ", '" << o.name << "'}";
    }
};
void println(auto rem, const auto& v)
{
    for (std::cout << rem; const auto& e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}
int main()
{
    // nota: no ordenado, solo particionado con respecto a S definido abajo
    std::vector<S> vec
    {
        {1,'A'}, {2,'B'}, {2,'C'}, {2,'D'}, {4, 'D'}, {4,'G'}, {3,'F'}
    };
    const S value{2, '?'};
    namespace ranges = std::ranges;
    auto a = ranges::equal_range(vec, value);
    println("1. ", a);
    auto b = ranges::equal_range(vec.begin(), vec.end(), value);
    println("2. ", b);
    auto c = ranges::equal_range(vec, 'D', ranges::less {}, &S::name);
    println("3. ", c);
    auto d = ranges::equal_range(vec.begin(), vec.end(), 'D', ranges::less {}, &S::name);
    println("4. ", d);
    using CD = std::complex<double>;
    std::vector<CD> nums{{1, 0}, {2, 2}, {2, 1}, {3, 0}, {3, 1}};
    auto cmpz = [](CD x, CD y) { return x.real() < y.real(); };
    #ifdef __cpp_lib_algorithm_default_value_type
        auto p3 = ranges::equal_range(nums, {2, 0}, cmpz);
    #else
        auto p3 = ranges::equal_range(nums, CD{2, 0}, cmpz);
    #endif
    println("5. ", p3);
}

Salida:

1. {2, 'B'} {2, 'C'} {2, 'D'}
2. {2, 'B'} {2, 'C'} {2, 'D'}
3. {2, 'D'} {4, 'D'}
4. {2, 'D'} {4, 'D'}
5. (2,2) (2,1)

Véase también

devuelve un iterador al primer elemento no menor que el valor dado
(objeto función de algoritmo)
devuelve un iterador al primer elemento mayor que cierto valor
(objeto función de algoritmo)
determina si un elemento existe en un rango parcialmente ordenado
(objeto función de algoritmo)
divide un rango de elementos en dos grupos
(objeto función de algoritmo)
determina si dos conjuntos de elementos son iguales
(objeto función de algoritmo)
devuelve el rango de elementos que coinciden con una clave específica
(plantilla de función)