std::ranges::unique(3)
β¨ NAME β¨
std::ranges::unique β std::ranges::unique. That's the name, and honestly it's iconic. This page comes from the C++ Standard Libary manual (yes, "Libary", we're keeping the spelling, it's canon π
).
πΈ Synopsis πΈ
Defined in header <algorithm>. Call signature, bestie:
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 >
(1) (since C++20)
constexpr ranges::subrange<I>
unique( I first, S last, C comp = {}, Proj proj = {} );
template< ranges::forward_range R, class Proj = std::identity,
std::indirect_equivalence_relation<std::projected<ranges::iterator_t<R>, Proj>>
C = ranges::equal_to >
(2) (since C++20)
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>
unique( R&& r, C comp = {}, Proj proj = {} );
- Eliminates all except the first element from every consecutive group of equivalent elements from the range
[first, last)and returns a subrange[ret, last), whereretis a past-the-end iterator for the new end of the range. Two consecutive elements*(i - 1)and*iare considered equivalent ifstd::invoke(comp, std::invoke(proj, *(i - 1)), std::invoke(proj, *i)) == true, whereiis an iterator in the range[first + 1, last). - Same as (1), but uses
ras the range, as if usingranges::begin(r)asfirst, andranges::end(r)aslast.
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. iykyk π«Ά
π Parameters π
first,lastβ the range of elements to processrβ the range of elements to processcompβ the binary predicate to compare the projected elementsprojβ the projection to apply to the elements
π Return value π
Returns {ret, last}, where ret is a past-the-end iterator for the new end of the range. Slay. β¨
π₯ Complexity π₯
For nonempty ranges, exactly ranges::distance(first, last) - 1 applications of the corresponding predicate comp and no more that twice as many applications of any projection proj. (Yes, "that" is in the original, we are not fixing it, periodt. π)
π¦ Notes π¦
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. Relative order of the elements that remain is preserved and the physical size of the container is unchanged. Iterators in [ret, last) (if any) are still dereferenceable, but the elements themselves have unspecified values (as per MoveAssignable post-condition).
A call to ranges::unique is sometimes followed by a call to a containerβs erase member function, which erases the unspecified values and reduces the physical size of the container to match its new logical size. These two invocations together model the Eraseβremove idiom.
π§ Possible implementation π§
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 {};
π Example π
// Run this code
#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()
{
// a vector containing several duplicated elements
std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
print(id {1}, v);
// remove consecutive (adjacent) duplicates
const auto ret = std::ranges::unique(v);
// v now holds {1 2 1 3 4 5 4 x x x}, where 'x' is indeterminate
v.erase(ret.begin(), ret.end());
print(id {2}, v);
// sort followed by unique, to remove all duplicates
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 now holds {1 2 3 4 5 x x}, where 'x' is indeterminate
v.erase(first, last);
print(id {4}, v);
// unique with custom comparison and projection
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,
// consider two complex nums equal if their real parts are equal by module:
[](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);
}
β Output β
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)
π See also π
ranges::unique_copy(C++20) β creates a copy of some range of elements that contains no consecutive duplicates (niebloid)ranges::adjacent_find(C++20) β finds the first two adjacent items that are equal (or satisfy a given predicate) (niebloid)ranges::remove,ranges::remove_if(C++20) β removes elements satisfying specific criteria (niebloid)uniqueβ removes consecutive duplicate elements in a range (function template)uniqueβ removes consecutive duplicate elements (public member function ofstd::list<T,Allocator>)uniqueβ removes consecutive duplicate elements (public member function ofstd::forward_list<T,Allocator>)
source/version: http://cppreference.com β date: 2024.06.10. That's the footer info, bestie, byeee ππ«Ά
π¦ 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