Namespaces
Variants

std::ranges::unique

cppreference.net에서
 
 
알고리즘 라이브러리
제약된 알고리즘 및 범위에 대한 알고리즘 (C++20)
제약된 알고리즘, 예: ranges::copy, ranges::sort, ...
정렬 및 관련 연산
분할 연산
(C++11)    

정렬 연산
이진 검색 연산
(분할된 범위에 대해)
집합 연산 (정렬된 범위에 대해)
병합 연산 (정렬된 범위에 대해)
힙 연산
최소/최대 연산
(C++11)
(C++17)
사전식 비교 연산
순열 연산


 
제약된 알고리즘
이 메뉴의 모든 이름은 네임스페이스에 속합니다. std::ranges
비수정 시퀀스 연산
수정 시퀀스 연산
분할 연산
정렬 연산
이진 검색 연산 (정렬된 범위에 대해)
       
       
집합 연산 (정렬된 범위에 대해)
힙 연산
최소/최대 연산
       
       
순열 연산
폴드 연산
수치 연산
(C++23)            
초기화되지 않은 저장소에 대한 연산
반환 유형
 
헤더에 정의됨<algorithm>
호출 시그니처
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) (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) (C++20부터)
1) 범위 [first, last)에서 동등한 요소들의 각 연속 그룹에서 첫 번째 요소를 제외한 모든 요소를 제거하고 부분범위 [ret, last)을 반환합니다. 여기서 ret는 범위의 새로운 끝을 가리키는 지나간-끝 반복자입니다.
두 개의 연속 요소 *(i - 1)과 *i은 std::invoke(comp, std::invoke(proj, *(i - 1)), std::invoke(proj, *i)) == true인 경우 동등한 것으로 간주됩니다. 여기서 i는 범위 [first + 1, last) 내의 반복자입니다.
2) (1)과 동일하지만, r를 범위로 사용합니다. 마치 ranges::begin(r)을 first로 사용하고 ranges::end(r)을 last로 사용하는 것과 같습니다.

이 페이지에 설명된 함수형 엔터티는 알고리즘 함수 객체 (비공식적으로 niebloids라고 함)입니다. 즉:

  • 명시적 템플릿 인자 목록은 이들 중 어느 것을 호출할 때도 지정할 수 없습니다.
  • 이들 중 어느 것도 인자 종속 조회에 표시되지 않습니다.
  • 이들 중 하나가 정규 비한정 조회에 의해 함수 호출 연산자의 왼쪽에 있는 이름으로 발견되면 인자 종속 조회가 억제됩니다.

매개변수

first, last - 처리할 요소들의 범위 를 정의하는 반복자-감시자 쌍
r - 처리할 요소들의 범위
comp - 투영된 요소들을 비교하기 위한 이항 조건자
proj - 요소들에 적용할 투영

반환값

{ ret, last } 를 반환합니다. 여기서 ret 는 범위의 새로운 끝을 지나는 past-the-end 반복자입니다.

복잡도

비어 있지 않은 범위의 경우, 정확히 ranges:: distance ( first, last ) - 1 번의 해당 predicate comp 적용과, 어떤 projection proj 도 최대 두 배 이하로 적용됩니다.

참고 사항

제거는 범위 내 요소들을 이동 대입(move assignment)을 통해 이동시킴으로써 수행되며, 제거되지 않을 요소들이 범위의 시작 부분에 나타나도록 합니다. 남아 있는 요소들의 상대적 순서는 유지되며 컨테이너의 물리적 크기는 변경되지 않습니다. [ ret , last ) 범위의 반복자(있는 경우)는 여전히 역참조 가능하지만, 요소 자체는 지정되지 않은 값을 가집니다( MoveAssignable 사후 조건에 따름).

ranges::unique 에 대한 호출은 때때로 컨테이너의 erase 멤버 함수 호출 뒤에 이루어지며, 이는 지정되지 않은 값을 지우고 컨테이너의 물리적 크기를 새로운 논리적 크기에 맞게 축소합니다. 이 두 호출을 함께 사용하면 Erase–remove 관용구 를 구현하는 모델이 됩니다.

가능한 구현

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 {};

예제

#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()
{
    // 여러 중복 요소를 포함하는 벡터
    std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
    print(id {1}, v);
    // 연속된 (인접한) 중복 제거
    const auto ret = std::ranges::unique(v);
    // v는 이제 {1 2 1 3 4 5 4 x x x}를 보유, 여기서 'x'는 불확정 값
    v.erase(ret.begin(), ret.end());
    print(id {2}, v);
    // 모든 중복을 제거하기 위한 정렬 후 unique 적용
    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는 이제 {1 2 3 4 5 x x}를 보유, 여기서 'x'는 불확정 값
    v.erase(first, last);
    print(id {4}, v);
    // 사용자 정의 비교 및 투영을 사용한 unique
    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,
        // 두 복소수가 실수부의 절대값이 같으면 동일한 것으로 간주:
        [](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);
}

출력:

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)

참고 항목

연속적인 중복 요소가 없는 일부 범위의 복사본을 생성합니다
(알고리즘 함수 객체)
서로 인접한 두 항목이 같거나(또는 주어진 조건자를 만족하는) 첫 번째 쌍을 찾습니다
(알고리즘 함수 객체)
특정 기준을 만족하는 요소들을 제거합니다
(알고리즘 함수 객체)
범위에서 연속적인 중복 요소를 제거합니다
(함수 템플릿)
연속적인 중복 요소를 제거합니다
( std::list<T,Allocator> 의 public 멤버 함수)
연속적인 중복 요소를 제거합니다
( std::forward_list<T,Allocator> 의 public 멤버 함수)