Namensräume
Varianten
Aktionen

std::ranges::unique

Von cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
Algorithmenbibliothek
Beschränkte Algorithmen und Algorithmen für Bereiche (C++20)
Beschränkte Algorithmen, z.B. ranges::copy, ranges::sort, ...
Ausführungsrichtlinien (C++17)
Nicht-modifizierende Sequenzoperationen
Stapeloperationen
(C++17)
Suchoperationen
(C++11)                (C++11)(C++11)

Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Generierungsoperationen
Entfernungsoperationen
Ordnungsändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Zusammenführungsoperationen (auf sortierten Bereichen)
Heapoperationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikographische Vergleichsoperationen
Permutationsoperationen
C-Bibliothek
Numerische Operationen
Operationen auf uninitialisiertem Speicher
 
Eingeschränkte Algorithmen
Alle Namen in diesem Menü gehören zum Namespace std::ranges
Nicht-modifizierende Sequenzoperationen
Modifizierende Sequenzoperationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen (auf sortierten Bereichen)
       
       
Mengenoperationen (auf sortierten Bereichen)
Heapoperationen
Minimum/Maximum-Operationen
       
       
Permutationsoperationen
Faltoperationen
Operationen auf uninitialisiertem Speicher
Rückgabetypen
 
Definiert in Header <algorithm>
Aufruf-Signatur
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) Eliminiert alle bis auf das erste Element aus jeder aufeinanderfolgenden Gruppe äquivalenter Elemente aus dem Bereich [firstlast) und gibt einen Unterbereich [retlast) 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 + 1last) ist.
2) Wie (1), aber verwendet r als Bereich, so als ob ranges::begin(r) als first und ranges::end(r) als last verwendet würden.

Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithmus-Funktionsobjekte (informell als niebloids bekannt), d.h.

Inhalt

[bearbeiten] 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 Projektion, die auf die Elemente angewendet werden soll

[bearbeiten] Rückgabewert

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

[bearbeiten] Komplexität

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

[bearbeiten] Anmerkungen

Die Entfernung erfolgt durch Verschieben (mittels Zuweisung durch Verschieben) der Elemente im Bereich so, 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 ändert sich nicht. Iteratoren in [retlast) (falls vorhanden) sind immer noch dereferenzierbar, aber die Elemente selbst haben unspezifizierte Werte (gemäß den Post-Bedingungen von MoveAssignable).

Ein Aufruf von ranges::unique wird manchmal von einem Aufruf der erase-Memberfunktion eines Containers gefolgt, der die unspezifizierten Werte löscht und die *physische* Größe des Containers auf seine neue *logische* Größe reduziert. Diese beiden Aufrufe zusammen modellieren das Erase–remove-Idiom.

[bearbeiten] 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 {};

[bearbeiten] 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()
{
    // 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);
}

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)

[bearbeiten] Siehe auch

Erstellt eine Kopie eines Bereichs von Elementen, die keine aufeinanderfolgenden Duplikate enthält
(Algorithmus-Funktionsobjekt)[edit]
Findet die ersten beiden benachbarten Elemente, die gleich sind (oder eine gegebene Bedingung erfüllen)
(Algorithmus-Funktionsobjekt)[edit]
entfernt Elemente, die bestimmte Kriterien erfüllen
(Algorithmus-Funktionsobjekt)[edit]
Entfernt aufeinanderfolgende doppelte Elemente in einem Bereich
(Funktionstemplate) [edit]
entfernt aufeinanderfolgende doppelte Elemente
(öffentliche Memberfunktion von std::list<T,Allocator>) [bearbeiten]
entfernt aufeinanderfolgende doppelte Elemente
(öffentliche Memberfunktion von std::forward_list<T,Allocator>) [bearbeiten]