Verketten von zwei std :: Vektoren

Wie verkette ich zwei std :: vector s?

469
@lecaruyer Sie erkennen, dass Sie gerade eine Frage markiert haben, die zwei Jahre zuvor als Duplikat gestellt wurde
hinzugefügt der Autor eshirima, Quelle
@FauChristian: Nein, es kann aus Sicht der Effizienz keine Verwendung geben. Der Vektorspeicher muss kontinuierlich sein, was Ihnen vorgeschlagen wird, ist unmöglich. Wenn Sie "etwas ausgeklügeltes Teilen der Verwaltung der Knoten" wünschen, und wenn Sie die Vektorklasse auf solch eine Weise ändern würden, würden Sie mit einer Deque enden. Selbst dann ist es sehr schwierig, den Speicher in der vorgeschlagenen Weise wiederzuverwenden, auch wenn es etwas praktikabler wird. Ich denke nicht, dass es derzeit implementiert ist. Die Hauptsache ist, dass bei einer solchen Freigabe von Managementknoten
hinzugefügt der Autor Cookie, Quelle
Die gegebenen Antworten verketten sich nicht. Sie fügen eine Kopie an. Es kann (aus Effizienzgesichtspunkten) sinnvoll sein, eine std :: vector verkettete Methode zu erstellen, allerdings würde dies eine ausgefeilte gemeinsame Nutzung der Verwaltung der Knoten erfordern, und das ist wahrscheinlich der Grund, warum dies noch nicht geschehen ist.
hinzugefügt der Autor FauChristian, Quelle
Bin ich der Einzige, der sich fragt, warum dies nicht als a + b oder a.concat (b) in der Standardbibliothek implementiert ist? Möglicherweise wäre die Standardimplementierung nicht optimal, aber jede Array-Verkettung muss nicht mikrooptimiert werden
hinzugefügt der Autor oseiskar, Quelle

16 Antworten

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
531
hinzugefügt
Wenn Sie mehrere Vektoren zu einem verketten, ist es hilfreich, zuerst reserve auf dem Zielvektor aufzurufen?
hinzugefügt der Autor Faheem Mitha, Quelle
@Aidin ich sehe. Danke für die Klarstellung.
hinzugefügt der Autor Faheem Mitha, Quelle
@ Khaur: Das ist erschreckend bis zu dem Punkt, es ist schwer zu glauben. Es ist extrem trivial, wenn eine Implementierung erkennt, dass die Iteratoren einen wahlfreien Zugriff haben, die Größe berechnen und den benötigten Speicherplatz vorreservieren. Ich denke, MSFT macht das sogar für Vorwärts-Iteratoren.
hinzugefügt der Autor Mooing Duck, Quelle
@AlexanderRafferty: Nur wenn vector1.capacity ()> = 2 * vector1.size() . Das ist atypisch, wenn Sie nicht std :: vector :: reserve() aufgerufen haben. Andernfalls wird der Vektor neu zugewiesen, wodurch die Iteratoren ungültig werden, die als Parameter 2 und 3 übergeben wurden.
hinzugefügt der Autor Drew Dormann, Quelle
Ich habe eine Frage. Funktioniert das, wenn vector1 und vector2 die gleichen Vektoren sind?
hinzugefügt der Autor Alexander Rafferty, Quelle
Ich würde nur Code hinzufügen, um zuerst die Anzahl der Elemente zu erhalten, die jeder Vektor enthält, und setze vector1 so, dass es derjenige ist, der den größten hält. Wenn Sie es anders machen, machen Sie viel unnötiges Kopieren.
hinzugefügt der Autor Joe Pineda, Quelle
Es ist schade, dass es in der Standardbibliothek keinen prägnanteren Ausdruck gibt. .concat oder + = oder so
hinzugefügt der Autor nmr, Quelle
@FaheemMitha: Da Argumente von einfügen Vektoren sind, wissen sie bereits, wie viele Elemente voraus sind und werden sie selbst behandeln. Wenn wir andere Dinge wie das Array einfügen würden, wäre es nützlich, zuerst das Leerzeichen zu reservieren.
hinzugefügt der Autor Aidin, Quelle
@MooingDuck Sie haben Recht, ich habe den Dispatcher verpasst und dachte, dass die Eingabe-Iterator-Version für alle Arten von Iteratoren angewendet wird. Die Forward-Iterator-Version macht viel mehr Zeug. Danke, dass du es aufgezeigt hast, ich habe meinen ursprünglichen Kommentar gelöscht, damit er nicht ohne deinen erscheint.
hinzugefügt der Autor Khaur, Quelle

Ich würde die Funktion einfügen verwenden, etwa so:

vector a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
112
hinzugefügt

Wenn Sie C ++ 11 verwenden und die Elemente verschieben und nicht nur kopieren möchten, können Sie std :: move_iterator ( http://en.cppreference.com/w/cpp/iterator/move_iterator ) zusammen mit dem Einfügen (oder Kopieren):

#include 
#include 
#include 

int main(int argc, char** argv) {
  std::vector dest{1,2,3,4,5};
  std::vector src{6,7,8,9,10};

 //Move elements from src to dest.
 //src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

 //Print out concatenated vector.
  std::copy(
      dest.begin(),
      dest.end(),
      std::ostream_iterator(std::cout, "\n")
    );

  return 0;
}

Dies wird für das Beispiel mit Ints nicht effizienter sein, da das Verschieben von ihnen nicht effizienter ist als das Kopieren von ihnen, aber für eine Datenstruktur mit optimierten Bewegungen kann vermieden werden, unnötige Zustände zu kopieren:

#include 
#include 
#include 

int main(int argc, char** argv) {
  std::vector> dest{{1,2,3,4,5}, {3,4}};
  std::vector> src{{6,7,8,9,10}};

 //Move elements from src to dest.
 //src is left in undefined but safe-to-destruct state.
  dest.insert(
      dest.end(),
      std::make_move_iterator(src.begin()),
      std::make_move_iterator(src.end())
    );

  return 0;
}

Nach dem Verschieben bleibt das Element von src in einem undefinierten, aber zerstörungssicheren Zustand und seine früheren Elemente wurden am Ende direkt in das neue Element von dest übertragen.

112
hinzugefügt
Die Methode std :: make_move_iterator() half mir beim Versuch, std :: vectors von std :: unique_ptr zu verketten.
hinzugefügt der Autor Knitschi, Quelle

Oder Sie könnten verwenden:

std::copy(source.begin(), source.end(), std::back_inserter(destination));

Dieses Muster ist nützlich, wenn die beiden Vektoren nicht genau die gleiche Art von Ding enthalten, weil Sie anstelle von std :: back_inserter etwas verwenden können, um von einem Typ in den anderen zu konvertieren.

70
hinzugefügt
@Yogesh: gewährt, aber es gibt nichts, was Sie daran hindert, zuerst reserve aufzurufen. Der Grund, warum std :: copy manchmal nützlich ist, ist, wenn Sie etwas anderes als back_inserter verwenden möchten.
hinzugefügt der Autor Roger Lipscombe, Quelle
Wenn Sie "Mehrfachzuweisungen" sagen, ist das wahr - aber die Anzahl der Zuordnungen ist schlimmstenfalls log (Anzahl der hinzugefügten Einträge) - was bedeutet, dass die Kosten für das Hinzufügen eines Eintrags in der Anzahl der hinzugefügten Einträge konstant sind. (Machen Sie sich im Grunde keine Sorgen, es sei denn, das Profil zeigt, dass Sie eine Reserve benötigen).
hinzugefügt der Autor Martin Bonner, Quelle
Möglicherweise möchten Sie stattdessen std :: transform verwenden.
hinzugefügt der Autor Martin Broadhurst, Quelle
Die Kopiermethode ist nicht so ein guter Weg. Es ruft push_back mehrere Male auf, was bedeutet, dass wenn viele Elemente eingefügt werden müssen, dies mehrere Umverteilungen bedeuten kann. Es ist besser, insert zu verwenden, da die Vektorimplementierung eine Optimierung durchführen kann, um Neuzuweisungen zu vermeiden. Es könnte Speicher reservieren, bevor mit dem Kopieren begonnen wird
hinzugefügt der Autor Yogesh Arora, Quelle
std::vector first;
std::vector second;

first.insert(first.end(), second.begin(), second.end());
30
hinzugefügt

Mit C ++ 11 würde ich bevorzugen, um Vektor b an a anzuhängen:

std::move(b.begin(), b.end(), std::back_inserter(a));

wenn a und b nicht überlappt sind und b nicht mehr verwendet wird.

27
hinzugefügt
@MartinBonner Danke, dass du das erwähnt hast. Wahrscheinlich sollte ich zurück zum alten einfügen Weg, der sicherer ist.
hinzugefügt der Autor Deqing, Quelle
Fügen Sie einfach folgende Kopfzeile hinzu: #include
hinzugefügt der Autor Manohar Reddy Poreddy, Quelle
Undefiniertes Verhalten, wenn a tatsächlich b ist (was in Ordnung ist, wenn Sie wissen, dass das nie passieren kann - aber es wert ist, dass Sie es in allgemeinem Code beachten).
hinzugefügt der Autor Martin Bonner, Quelle
Ah, die andere std :: move. Sehr verwirrend, wenn man es das erste Mal sieht.
hinzugefügt der Autor xaxxon, Quelle

Ich bevorzuge eine, die bereits erwähnt wurde:

a.insert(a.end(), b.begin(), b.end());

Aber wenn Sie C ++ 11 verwenden, gibt es einen generischen Weg:

a.insert(std::end(a), std::begin(b), std::end(b));

Auch nicht Teil einer Frage, aber es ist ratsam, reserve vor dem Anhängen für eine bessere Leistung. Und wenn Sie Vektor mit sich selbst verketten, ohne es zu reservieren, sollten Sie reservieren .


Also im Grunde, was du brauchst:

template 
void Append(std::vector& a, const std::vector& b)
{
    a.reserve(a.size() + b.size());
    a.insert(a.end(), b.begin(), b.end());
}
18
hinzugefügt
@Asu ADL fügt nur dann std :: hinzu, wenn der Typ a von std stammt, was den generischen Aspekt vereitelt.
hinzugefügt der Autor Potatoswatter, Quelle
std :: wird durch argumentabhängige Suche . Ende (a) wird ausreichen.
hinzugefügt der Autor Asu, Quelle
guter Punkt. in diesem Fall ist es ein Vektor, also würde es sowieso funktionieren, aber ja, das ist eine bessere Lösung.
hinzugefügt der Autor Asu, Quelle

Sie sollten vector :: einfügen verwenden

v1.insert(v1.end(), v2.begin(), v2.end());
5
hinzugefügt

Wenn Sie an einer starken Ausnahmegarantie interessiert sind (wenn der Kopierkonstruktor eine Ausnahme auslösen kann):

template
inline void append_copy(std::vector& v1, const std::vector& v2)
{
    const auto orig_v1_size = v1.size();
    v1.reserve(orig_v1_size + v2.size());
    try
    {
        v1.insert(v1.end(), v2.begin(), v2.end());
    }
    catch(...)
    {
        v1.erase(v1.begin() + orig_v1_size, v1.end());
        throw;
    }
}

Ähnliches append_move mit starker Garantie kann im Allgemeinen nicht implementiert werden, wenn der move-Konstruktor des Vektorelements werfen kann (was unwahrscheinlich ist, aber immer noch).

4
hinzugefügt
einfügen verarbeitet dies bereits. Dieser Aufruf von erase ist gleichbedeutend mit einer resize .
hinzugefügt der Autor Potatoswatter, Quelle
Ist es nicht möglich, v1.erase (... auch zu werfen?
hinzugefügt der Autor camelCase, Quelle
vector v1 = {1, 2, 3, 4, 5};
vector v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
3
hinzugefügt
Während dieses Code-Snippet das Problem lösen kann, erklärt es nicht, warum oder wie es die Frage beantwortet. Bitte fügen Sie eine Erklärung für Ihren Code hinzu , da dies wirklich dazu beiträgt, die Qualität Ihres Posts zu verbessern. Flaggers/Reviewer: Für Code-only-Antworten wie diesen, downvote, nicht löschen! a> (Hinweis: Diese Antwort ist möglicherweise einfach genug, um eine Erklärung und somit Downvotes überflüssig zu machen. Sie können dennoch eine Erklärung hinz
hinzugefügt der Autor Scott Weldon, Quelle

Fügen Sie dieses zu Ihrer Header-Datei hinzu:

template  vector concat(vector &a, vector &b) {
    vector ret = vector();
    copy(a.begin(), a.end(), back_inserter(ret));
    copy(b.begin(), b.end(), back_inserter(ret));
    return ret;
}

und benutze es so:

vector a = vector();
vector b = vector();

a.push_back(1);
a.push_back(2);
b.push_back(62);

vector r = concat(a, b);

r enthält [1,2,62]

2
hinzugefügt
Ich weiß nicht, warum das abgelehnt wurde. Es ist vielleicht nicht der effizienteste Weg, dies zu tun, aber es ist nicht falsch und effektiv.
hinzugefügt der Autor leeor_net, Quelle

Mit Bereich v3 haben Sie möglicherweise eine faule Verkettung:

ranges::view::concat(v1, v2)

Demo.

2
hinzugefügt

Hier ist eine allgemeine Lösung mit C ++ 11 move-Semantik:

template 
std::vector concat(const std::vector& lhs, const std::vector& rhs)
{
    if (lhs.empty()) return rhs;
    if (rhs.empty()) return lhs;
    std::vector result {};
    result.reserve(lhs.size() + rhs.size());
    result.insert(result.cend(), lhs.cbegin(), lhs.cend());
    result.insert(result.cend(), rhs.cbegin(), rhs.cend());
    return result;
}

template 
std::vector concat(std::vector&& lhs, const std::vector& rhs)
{
    lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
    return std::move(lhs);
}

template 
std::vector concat(const std::vector& lhs, std::vector&& rhs)
{
    rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
    return std::move(rhs);
}

template 
std::vector concat(std::vector&& lhs, std::vector&& rhs)
{
    if (lhs.empty()) return std::move(rhs);
    lhs.insert(lhs.cend(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
    return std::move(lhs);
}

Beachten Sie, wie sich dies von append unterscheidet, das in einen vector eingefügt wird.

1
hinzugefügt

Wenn das, was Sie suchen, eine Möglichkeit ist, einen Vektor nach der Erstellung an einen anderen anzuhängen, vector :: insertion ist Ihre beste Wahl, da es mehrfach beantwortet wurde, zum Beispiel:

vector first = {13};
const vector second = {42};

first.insert(first.end(), second.cbegin(), second.cend());

Sadly there's no way to construct a const vector, as above you must construct and then insert.


If what you're actually looking for is a container to hold the concatenation of these two vectors, there may be something better available to you, if:

  1. Ihr vector enthält Primitive
  2. Ihre enthaltenen Primitive haben eine Größe von 32 Bit oder kleiner
  3. Sie möchten einen const Container

Wenn die obigen Angaben zutreffen, würde ich vorschlagen, den basic_string Wer ist char_type entspricht der Größe des Grundelements in Ihrem vector . Sie sollten static_assert in Ihren Code einfügen validiere diese Größen konsistent:

static_assert(sizeof(char32_t) == sizeof(int));

Mit dieser Feststellung können Sie Folgendes tun:

const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());

For more information on the differences between string and vector you can look here: https://stackoverflow.com/a/35558008/2642059

For a live example of this code you can look here: http://ideone.com/7Iww3I

0
hinzugefügt

Um ehrlich zu sein, könnten Sie zwei Vektoren durch Kopieren von Elementen von zwei Vektoren in den anderen verketten oder nur einen von zwei Vektoren anhängen! Es hängt von deinem Ziel ab.

Method 1: Assign new vector with its size is the sum of two original vectors' size.

vector concat_vector = vector();
concat_vector.setcapacity(vector_A.size() + vector_B.size());
// Loop for copy elements in two vectors into concat_vector

Method 2: Append vector A by adding/inserting elements of vector B.

// Loop for insert elements of vector_B into vector_A with insert() 
function: vector_A.insert(vector_A .end(), vector_B.cbegin(), vector_B.cend());
0
hinzugefügt
Was fügt Ihre Antwort hinzu, die in anderen Antworten noch nicht enthalten ist?
hinzugefügt der Autor Mat, Quelle
Wenn der/die ursprüngliche (n) Vektor (e) danach nicht mehr benötigt werden, ist es besser, std :: move_iterator zu verwenden, damit die Elemente verschoben und nicht kopiert werden. (Siehe de.cppreference.com/w/cpp/iterator/move_iterator ) .
hinzugefügt der Autor tmlen, Quelle
@Mat: Fette Zeichen.
hinzugefügt der Autor marcv81, Quelle

Eine allgemeine Leistungssteigerung für Verkettung besteht darin, die Größe der Vektoren zu überprüfen. Und füge die kleinere mit der größeren ein.

//vector v1,v2;
if(v1.size()>v2.size()){
    v1.insert(v1.end(),v2.begin(),v2.end());
}else{
    v1.insert(v2.end(),v1.begin(),v1.end());
}
0
hinzugefügt