std :: back_inserter für ein std :: set?


93

Ich denke, das ist eine einfache Frage. Ich muss so etwas tun:

std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());

Funktioniert natürlich std::back_inserternicht, da es keine gibt push_back. std::inserterbraucht auch einen Iterator? Ich habe es nicht benutzt std::inserterund bin mir nicht sicher, was ich tun soll.

Hat jemand eine Idee?


Natürlich besteht meine andere Option darin, einen Vektor für zu verwenden s2und ihn später zu sortieren. Vielleicht ist das besser?

Antworten:


138

setnicht, push_backweil die Position eines Elements vom Komparator der Menge bestimmt wird. Verwenden std::inserterund übergeben Sie es .begin():

std::set<int> s1, s2;
s1 = getAnExcitingSet();
transform(s1.begin(), s1.end(), 
          std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());

Der Einfügeiterator ruft dann auf, s2.insert(s2.begin(), x)wo xder Wert ist, der beim Schreiben an den Iterator übergeben wird. Das Set verwendet den Iterator als Hinweis, wo eingefügt werden soll. Sie könnten auch verwenden s2.end().


2
inserter(vec, vec.end())Warum verwendet jemand back_inserter überhaupt, da er auch für Vektoren funktioniert?
NHDaly

7
@NHDaly: weil back_inserter schneller ist
marton78

@ marton78 Aber sollte es nicht nur mit einem sehr kleinen Vorsprung schneller sein, wenn überhaupt? Das Aufrufen insertanstelle push_backeines Vektors sollte ungefähr identisch sein (O (1)), wenn keine Elemente verschoben werden müssen.
Felix Dombek

3
@FelixDombek Sie haben Recht, es wird nicht viel langsamer sein. v.insert(x, v.end())wird am Anfang einen zusätzlichen Zweig haben (weil es n Elemente bewegt, aber hier ist n Null). Die Verwendung von inserter1) kommuniziert jedoch eine andere Absicht als die Verwendung von push_back2) ist ungewöhnlich und lässt den Leser innehalten und denken, 3) sei eine vorzeitige Pessimisierung.
Marton78

0

2016 gab es einen Vorschlag für einen " inserterIterator mit nur einem Argument ". https://isocpp.org/files/papers/p0471r0.html . Ich konnte nicht feststellen, ob der Vorschlag fortgeschritten war. Ich denke es macht Sinn.

Im Moment kann dieses Verhalten die Maker-Funktion definieren:

template<class Container>
auto sinserter(Container& c){
    using std::end;
    return std::inserter(c, end(c));
}

Benutzt als:

std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});

Soll dies auf allen Standardcontainern funktionieren? Es funktioniert nicht mit std :: forward_list (der Compilerfehler lautet "forward_list hat kein Mitglied mit dem Namen 'insert'", innerhalb der Instanziierung von insert_iterator::operator=). Sollte es?
Don Hatch

@ DonHatch, alles was hat insert(und end). es scheint, dass es forward_listüberhaupt keine insertOperation gibt insert_after. Und selbst wenn das geändert wird, kann es nach dem Ende nicht eingefügt werden, denke ich. Kannst du nicht std::liststattdessen ein verwenden?
6.

Klar, ich persönlich brauche std :: forward_list nicht. Aber ich interessiere mich für ein generisches "Wie kopiere ich einen Container in einen anderen?" für alle Behälterpaare, für die es Sinn macht. Mein aktuelles Interesse gilt der Ausübung generischer Container-Allokatoren wie @HowardHinnants short_alloc.
Don Hatch

@ DonHatch, die Sache ist, dass es viele Varianten zu dieser Frage gibt. ("" Wie kopiere ich einen Container in einen anderen? "). Möchten Sie beispielsweise die ursprünglichen Werte beibehalten, Zuordnungen minimieren usw. Für den einfachsten Fall ist meiner Meinung nach die beste Antwort die Verwendung von Konstruktor des Containers, der zwei Iteratoren benötigt (die meisten Container können das aufnehmen) NewContaner new_container(old_other_container.begin(), old_other_container.end()).
alfC

1
Ja, std :: set ist kein SequentialContainer, und das ist in Ordnung :-) existing_list = std::list(c.begin(), c.end(), existing_list.get_allocator()) Sehr schön, ich denke, das ist meine Antwort. Prost!
Don Hatch
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.