Namespaces
Variants

std::ranges:: unique

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
Definiert im Header <algorithm>
Aufrufsignatur
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) (seit 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) (seit C++20)
1) Entfernt alle bis auf das erste Element aus jeder aufeinanderfolgenden Gruppe äquivalenter Elemente aus dem Bereich [ first , last ) und gibt einen Teilbereich [ ret , last ) zurück, wobei ret ein Past-the-End-Iterator für das neue Ende des Bereichs ist.
Zwei aufeinanderfolgende Elemente *(i - 1) und *i werden als äquivalent betrachtet, wenn std:: invoke ( comp, std:: invoke ( proj, * ( i - 1 ) ) , std:: invoke ( proj, * i ) ) == true , wobei i ein Iterator im Bereich [ first + 1 , last ) ist.
2) Gleich wie (1) , verwendet jedoch r als Bereich, als ob ranges:: begin ( r ) als first und ranges:: end ( r ) als last verwendet würde.

Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithm Function Objects (informell bekannt als Niebloids ), das heißt:

Inhaltsverzeichnis

Parameter

first, last - das Iterator-Sentinel-Paar, das den Bereich der zu verarbeitenden Elemente definiert
r - der Bereich der zu verarbeitenden Elemente
comp - das binäre Prädikat zum Vergleichen der projizierten Elemente
proj - die auf die Elemente anzuwendende Projektion

Rückgabewert

Gibt { ret, last } zurück, wobei ret ein Past-the-End-Iterator für das neue Ende des Bereichs ist.

Komplexität

Für nichtleere Bereiche genau ranges:: distance ( first, last ) - 1 Anwendungen des entsprechenden Prädikats comp und nicht mehr als doppelt so viele Anwendungen jeglicher Projektion proj .

Hinweise

Das Entfernen erfolgt durch Verschieben (mittels Verschiebezuweisung) der Elemente im Bereich in einer Weise, dass die nicht zu entfernenden Elemente am Anfang des Bereichs erscheinen. Die relative Reihenfolge der verbleibenden Elemente bleibt erhalten und die physische Größe des Containers bleibt unverändert. Iteratoren im Bereich [ ret , last ) (falls vorhanden) sind weiterhin dereferenzierbar, aber die Elemente selbst haben unspezifizierte Werte (gemäß der MoveAssignable Nachbedingung).

Ein Aufruf von ranges::unique wird manchmal gefolgt von einem Aufruf der erase -Memberfunktion eines Containers, welche die unspezifizierten Werte löscht und die physische Größe des Containers reduziert, um seiner neuen logischen Größe zu entsprechen. Diese beiden Aufrufe modellieren zusammen das Erase–remove Idiom .

Mögliche Implementierung

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

Beispiel

#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()
{
    // ein Vektor mit mehreren duplizierten Elementen
    std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
    print(id {1}, v);
    // entferne aufeinanderfolgende (benachbarte) Duplikate
    const auto ret = std::ranges::unique(v);
    // v enthält nun {1 2 1 3 4 5 4 x x x}, wobei 'x' undefiniert ist
    v.erase(ret.begin(), ret.end());
    print(id {2}, v);
    // sortieren gefolgt von unique, um alle Duplikate zu entfernen
    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 enthält nun {1 2 3 4 5 x x}, wobei 'x' undefiniert ist
    v.erase(first, last);
    print(id {4}, v);
    // unique mit benutzerdefiniertem Vergleich und Projektion
    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,
        // betrachte zwei komplexe Zahlen als gleich, wenn ihre Realteile im Modul gleich sind:
        [](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);
}

Ausgabe:

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)

Siehe auch

erstellt eine Kopie eines Bereichs von Elementen, die keine aufeinanderfolgenden Duplikate enthält
(Algorithmus-Funktionsobjekt)
findet die ersten zwei benachbarten Elemente, die gleich sind (oder ein gegebenes Prädikat erfüllen)
(Algorithmus-Funktionsobjekt)
entfernt Elemente, die bestimmte Kriterien erfüllen
(Algorithmus-Funktionsobjekt)
entfernt aufeinanderfolgende doppelte Elemente in einem Bereich
(Funktions-Template)
entfernt aufeinanderfolgende doppelte Elemente
(öffentliche Elementfunktion von std::list<T,Allocator> )
entfernt aufeinanderfolgende doppelte Elemente
(öffentliche Elementfunktion von std::forward_list<T,Allocator> )