c ++ STL Satzunterschied

Antworten:

135

Ja, es ist in <algorithm>und heißt : std::set_difference. Die Verwendung ist:

#include <algorithm>
#include <set>
#include <iterator>
// ...
std::set<int> s1, s2;
// Fill in s1 and s2 with values
std::set<int> result;
std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(),
    std::inserter(result, result.end()));

Am Ende enthält das Set resultdie s1-s2.

PierreBdR
quelle
+1. Leider, als ich das brauchte, gab ich auf und rollte meine eigene Schleife :(
Peterchen
45
Übrigens, wenn Sie set_difference für eine nicht assoziative Containerklasse verwenden, z. B. einen Vektor, stellen Sie sicher, dass die Elemente in beiden Containern zuerst sortiert werden ...
paxos1977
4
#include <algorithms> -> Keine solche Datei, sollte <algorithm> sein?
stefanB
für set <string> musste ich std :: insert_iterator <set <string >> (...) qualifizieren
stefanB
@stefanB: Der erste Kommentar ist korrekt, und der zweite: Es ist üblich, std::inserterstattdessen zu verwenden . Es ist keine Qualifikation erforderlich, da dies eine Funktion ist.
Rlbond
11

Ja, der Algorithmus-Header enthält eine Funktion set_difference .

Bearbeitungen:

Zu Ihrer Information, die eingestellte Datenstruktur kann diesen Algorithmus effizient verwenden, wie in der Dokumentation angegeben . Der Algorithmus funktioniert auch nicht nur für Mengen, sondern für jedes Iteratorpaar über sortierten Sammlungen.

Wie andere bereits erwähnt haben, handelt es sich hierbei um einen externen Algorithmus, nicht um eine Methode. Vermutlich ist das gut für Ihre Anwendung.

Herr Fooz
quelle
1
Es kann auf jedem Paar sortierter Behälter verwendet werden.
xtofl
4

Kein "Operator" im Sinne der Sprache, aber es gibt den Algorithmus set_difference in der Standardbibliothek:

http://www.cplusplus.com/reference/algorithm/set_difference.html

Natürlich sind auch die anderen grundlegenden Mengenoperationen vorhanden - (Vereinigung usw.), wie im Abschnitt "Siehe auch" am Ende des verlinkten Artikels vorgeschlagen.

philsquared
quelle
2

Die gewählte Antwort ist korrekt, weist jedoch einige Syntaxfehler auf.

Anstatt von

#include <algorithms>

verwenden

#include <algorithm>

Anstatt von

std::insert_iterator(result, result.end()));

verwenden

std::insert_iterator<set<int> >(result, result.end()));

quelle
9
oder einfach benutzenstd::inserter(result, result.end())
rlbond
2

Noch einmal, Boost zur Rettung:

#include <string>
#include <set>
#include <boost/range/algorithm/set_algorithm.hpp>

std::set<std::string> set0, set1, setDifference;
boost::set_difference(set0, set1, std::inserter(setDifference, setDifference.begin());

setDifference enthält set0-set1.

strickli
quelle
2

C ++ definiert keinen Satzdifferenzoperator, aber Sie können Ihren eigenen definieren (unter Verwendung des in anderen Antworten angegebenen Codes):

template<class T>
set<T> operator -(set<T> reference, set<T> items_to_remove)
{
    set<T> result;
    std::set_difference(
        reference.begin(), reference.end(),
        items_to_remove.begin(), items_to_remove.end(),
        std::inserter(result, result.end()));
    return result;
}
Astraujums
quelle
1

Nicht als Methode, aber es gibt die externe Algorithmusfunktion set_difference

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_difference(InputIterator1 first1, InputIterator1 last1,
                              InputIterator2 first2, InputIterator2 last2,
                              OutputIterator result);

http://www.sgi.com/tech/stl/set_difference.html

Ian G.
quelle
1

Alle Antworten, die ich hier sehe, sind O (n). Wäre das nicht besser?:

template <class Key, class Compare, class Allocator>   
std::set<Key, Compare, Allocator> 
set_subtract(std::set<Key, Compare, Allocator>&& lhs,
             const std::set<Key, Compare, Allocator>& rhs) {
    if (lhs.empty()) { return lhs; }
    // First narrow down the overlapping range:
    const auto rhsbeg = rhs.lower_bound(*lhs.begin());
    const auto rhsend = rhs.upper_bound(*lhs.rbegin());
    for (auto i = rhsbeg; i != rhsend; ++i) {
        lhs.erase(*i);
    }
    return std::move(lhs);
}

Das scheint das Richtige zu tun. Ich bin mir nicht sicher, wie ich mit dem Fall umgehen soll, dass Compareder Typ sein Verhalten nicht vollständig spezifiziert, wie wenn Comparees ein ist std::function<bool(int,int)>, aber abgesehen davon scheint dies richtig zu funktionieren und sollte wie O sein ((num überlappend) • log ( lhs.size())).

In dem Fall, lhsder nicht enthält *i, ist es wahrscheinlich möglich, weiter zu optimieren, indem eine O (log ( rhs.size())) - Suche nach dem nächsten Element von rhs> = dem nächsten Element von durchgeführt wird lhs. Das würde den Fall optimieren lhs = {0, 1000}und rhs = {1, 2, ..., 999}die Subtraktion in der Protokollzeit durchführen.

Ben
quelle
-1

können wir nur verwenden

 set_difference(set1.begin(), set1.end(), set2.begin(). set2,end(),std::back_inserter(result)).
user1830108
quelle
4
std::back_insertererfordert die push_back()Methode für den Zielcontainer result. Dies wird nicht funktionieren, wenn resulteinstd::set
Attila
1
Bitte stellen Sie keine Fragen in die Antworten.
user650261