std::ranges::nth_element(3)
π std::ranges::nth_element(3) β C++ Standard Library
okay so bestie, buckle up, because we're talking about std::ranges::nth_element from the C++ Standard Library, and honestly? it's giving niche but iconic π
β¨ NAME β¨
std::ranges::nth_element β yes that's literally it, that's the name, no notes π
πΈ SYNOPSIS πΈ
Miss thing lives in the header <algorithm>, and she has two call signatures. Let me lay them out for you, exactly, no gatekeeping π«Ά
Signature (1) β since C++20:
template< std::random_access_iterator I, std::sentinel_for<I> S,
class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<I, Comp, Proj>
constexpr I
nth_element( I first, I nth, S last, Comp comp = {}, Proj proj = {} );
Signature (2) β also since C++20:
template< ranges::random_access_range R,
class Comp = ranges::less, class Proj = std::identity >
requires std::sortable<iterator_t<R>, Comp, Proj>
constexpr ranges::borrowed_iterator_t<R>
nth_element( R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {} );
π¦ DESCRIPTION π¦
So what does she do? She reorders the elements in [first, last) so that all of the following is true, periodt:
- the element pointed at by
nthis changed to whatever element would occur in that position if[first, last)were sorted with respect tocompandproj. like, she's manifesting the position β¨ - all of the elements before this new
nthelement are less than or equal to the elements after the newnthelement. that is, for every iteratori,jin the ranges[first, nth),[nth, last)respectively, the expressionstd::invoke(comp, std::invoke(proj, *j), std::invoke(proj, *i))evaluates tofalse. yes that's the whole vibe check π - if
nth == lastthen the function has no effect. she does absolutely nothing, and honestly? valid π
Then the two flavors:
- elements are compared using the given binary comparison function object
compand projection objectproj. - same as (1), but uses
ras the range, as if usingranges::begin(r)asfirstandranges::end(r)aslast.
π§ the niebloid lore (iykyk)
the function-like entities described on this page are niebloids, that is:
- explicit template argument lists cannot be specified when calling any of them.
- none of them are visible to argument-dependent lookup.
- when any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
in practice, they may be implemented as function objects, or with special compiler extensions. no cap, that's the tea β
π Parameters π
first,lastβ the range of elements to reorderrβ the range of elements to reordernthβ the iterator defining the partition pointcompβ comparator used to compare the projected elementsprojβ projection to apply to the elements
π Return value π
- an iterator equal to
last. - same as (1) if
ris an lvalue or of aborrowed_rangetype. otherwise returnsstd::ranges::dangling. bestie watch out for the dangling one, that's the plot twist π
π₯ Complexity π₯
linear in ranges::distance(first, last) on average. she's efficient, she's lowkey humble about it π
β Notes β
the algorithm used is typically introselect, although other selection algorithms with suitable average-case complexity are allowed. so like, the vibe is introselect but she's not gonna fight you over it π
π Possible implementation π
see also the implementation in msvc stl, libstdc++, and libc++: (1) / (2). the girls are all doing it, respectfully π«Ά
π Example π
#include <algorithm>
#include <array>
#include <functional>
#include <iostream>
#include <ranges>
#include <string_view>
void print(std::string_view rem, std::ranges::input_range auto const& a)
{
for (std::cout << rem; const auto e : a)
std::cout << e << ' ';
std::cout << '\n';
}
int main()
{
std::array v{5, 6, 4, 3, 2, 6, 7, 9, 3};
print("Before nth_element: ", v);
std::ranges::nth_element(v, v.begin() + v.size() / 2);
print("After nth_element: ", v);
std::cout << "The median is: " << v[v.size() / 2] << '\n';
std::ranges::nth_element(v, v.begin() + 1, std::greater<int>());
print("After nth_element: ", v);
std::cout << "The second largest element is: " << v[1] << '\n';
std::cout << "The largest element is: " << v[0] << "\n\n";
using namespace std::literals;
std::array names
{
"Diva"sv, "Cornelius"sv, "Munro"sv, "Rhod"sv,
"Zorg"sv, "Korben"sv, "Bender"sv, "Leeloo"sv,
};
print("Before nth_element: ", names);
auto fifth_element{std::ranges::next(names.begin(), 4)};
std::ranges::nth_element(names, fifth_element);
print("After nth_element: ", names);
std::cout << "The 5th element is: " << *fifth_element << '\n';
}
Output β she ate and left zero crumbs π₯
Before nth_element: 5 6 4 3 2 6 7 9 3
After nth_element: 2 3 3 4 5 6 6 7 9
The median is: 5
After nth_element: 9 7 6 6 5 4 3 3 2
The second largest element is: 7
The largest element is: 9
Before nth_element: Diva Cornelius Munro Rhod Zorg Korben Bender Leeloo
After nth_element: Diva Cornelius Bender Korben Leeloo Rhod Munro Zorg
The 5th element is: Leeloo
π See also π
ranges::max_elementβ returns the largest element in a range (C++20) (niebloid)ranges::min_elementβ returns the smallest element in a range (C++20) (niebloid)ranges::partitionβ divides a range of elements into two groups (C++20) (niebloid)ranges::partial_sortβ sorts the first N elements of a range (C++20) (niebloid)nth_elementβ partially sorts the given range making sure that it is partitioned by the given element (function template)
ok that's the whole page bestie, go forth and partition π
and fr fr, this one's brought to you by http://cppreference.com, version 2024.06.10, page std::ranges::nth_element(3) β mwah, slay, go read it again if you need to π§ββοΈπ
β¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms