Concentreren van twee STD :: Vectoren

Hoe concateneer ik twee std::vectors?


Antwoord 1, Autoriteit 100%

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );

Antwoord 2, Autoriteit 28%

Als u C++ 11 gebruikt en de elementen wilt verplaatsen in plaats van ze alleen maar te kopiëren, kunt u std::move_iteratorsamen met insert (of kopie):

#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
  std::vector<int> dest{1,2,3,4,5};
  std::vector<int> 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<int>(std::cout, "\n")
    );
  return 0;
}

Dit zal niet efficiënter zijn voor het voorbeeld met Ints, omdat het verplaatsen van ze niet efficiënter is dan het kopiëren van ze, maar voor een data-structuur met geoptimaliseerde bewegingen, kan het voorkomen dat het onnodige staat wordt gekopieerd:

#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
  std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
  std::vector<std::vector<int>> 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;
}

Na de verplaatsing blijft het element van src in een ongedefinieerde maar veilige staat om te vernietigen, en zijn eerdere elementen werden aan het einde rechtstreeks overgebracht naar het nieuwe element van dest.


Antwoord 3, autoriteit 20%

Ik zou de insert-functiegebruiken, zoiets als:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());

Antwoord 4, autoriteit 10%

Of je zou kunnen gebruiken:

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

Dit patroon is handig als de twee vectoren niet precies hetzelfde type ding bevatten, omdat je iets kunt gebruiken in plaats van std::back_inserter om van het ene type naar het andere te converteren.


Antwoord 5, autoriteit 8%

Met C++11 zou ik het volgende prefereren om vector b aan a toe te voegen:

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

wanneer aen belkaar niet overlappen, en bniet meer wordt gebruikt.


Dit is std::movevan <algorithm>, niet de gebruikelijkestd::movevan <utility>.


Antwoord 6, autoriteit 5%

std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());

Antwoord 7, autoriteit 3%

Ik geef de voorkeur aan een die al genoemd is:

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

Maar als je C++11 gebruikt, is er nog een algemenere manier:

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

Ook geen onderdeel van een vraag, maar het is raadzaam om reservevoordat u toevoegt voor betere prestaties. En als u vector met zichzelf samenvoegt, mislukt het zonder te reserveren, dus u moet altijd reserve.


Dus eigenlijk wat je nodig hebt:

template <typename T>
void Append(std::vector<T>& a, const std::vector<T>& b)
{
    a.reserve(a.size() + b.size());
    a.insert(a.end(), b.begin(), b.end());
}

Antwoord 8, autoriteit 3%

Met range v3heb je misschien een luieaaneenschakeling :

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

Demo.


Antwoord 9, autoriteit 2%

Een algemene prestatieverbeteringvoor concatenate is het controleren van de grootte van de vectoren. En voeg de kleinere samen met de grotere.

//vector<int> v1,v2;
if(v1.size()>v2.size()) {
    v1.insert(v1.end(),v2.begin(),v2.end());
} else {
    v2.insert(v2.end(),v1.begin(),v1.end());
}

Antwoord 10, autoriteit 2%

Als u vectoren beknopt wilt kunnen samenvoegen, kunt u de operator +=overbelasten.

template <typename T>
std::vector<T>& operator +=(std::vector<T>& vector1, const std::vector<T>& vector2) {
    vector1.insert(vector1.end(), vector2.begin(), vector2.end());
    return vector1;
}

Dan kun je het zo noemen:

vector1 += vector2;

Antwoord 11

U moet vector::insert

gebruiken

v1.insert(v1.end(), v2.begin(), v2.end());

Antwoord 12

Als u geïnteresseerd bent in een sterke uitzonderingsgarantie (wanneer de copy-constructor een uitzondering kan genereren):

template<typename T>
inline void append_copy(std::vector<T>& v1, const std::vector<T>& 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;
    }
}

Vergelijkbare append_movemet sterke garantie kan in het algemeen niet worden geïmplementeerd als de move-constructor van het vectorelement kan gooien (wat onwaarschijnlijk is, maar toch).


Antwoord 13

Er is een algoritme std::mergevan C++17, wat heel gemakkelijk te gebruiken is wanneer de invoervectoren zijn gesorteerd,

Hieronder staat het voorbeeld:

#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
    //DATA
    std::vector<int> v1{2,4,6,8};
    std::vector<int> v2{12,14,16,18};
    //MERGE
    std::vector<int> dst;
    std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));
    //PRINT
    for(auto item:dst)
        std::cout<<item<<" ";
    return 0;
}

Antwoord 14

Voeg deze toe aan je headerbestand:

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

en gebruik het op deze manier:

vector<int> a = vector<int>();
vector<int> b = vector<int>();
a.push_back(1);
a.push_back(2);
b.push_back(62);
vector<int> r = concat(a, b);

r zal [1,2,62] bevatten


Antwoord 15

Als het uw doel eenvoudigweg is om het bereik van waarden te herhalen voor alleen-lezen doeleinden, is een alternatief om beide vectoren rond een proxy (O(1)) te wikkelen in plaats van ze te kopiëren (O(n)), zodat ze worden onmiddellijk als een enkele, aaneengesloten beschouwd.

std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B);  // ----> O(1)!
for (size_t i = 0; i < AB.size(); i++)
    std::cout << AB[i] << " ";  // ----> 1 2 3 4 5 10 20 30

Raadpleeg https://stackoverflow.com/a/55838758/2379625voor meer details, waaronder de ‘VecProxy ‘ implementatie evenals pro’s & nadelen.


Antwoord 16

Hier is een algemene oplossing met C++11 move-semantiek:

template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
    if (lhs.empty()) return rhs;
    if (rhs.empty()) return lhs;
    std::vector<T> 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 <typename T>
std::vector<T> concat(std::vector<T>&& lhs, const std::vector<T>& rhs)
{
    lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
    return std::move(lhs);
}
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, std::vector<T>&& rhs)
{
    rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
    return std::move(rhs);
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, std::vector<T>&& 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);
}

Merk op hoe dit verschilt van appending aan een vector.


Antwoord 17

vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));

Antwoord 18

U kunt uw eigen sjabloon voorbereiden voor + operator:

template <typename T> 
inline T operator+(const T & a, const T & b)
{
    T res = a;
    res.insert(res.end(), b.begin(), b.end());
    return res;
}

Volgende – gebruik gewoon +:

vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
    cout << x << " ";
cout << endl;

Dit voorbeeld geeft uitvoer:

1 2 3 4 5 6 7 8

Antwoord 19

Ik heb deze functie geïmplementeerd die een willekeurig aantal containers samenvoegt, van rvalue-referenties afwijkt en anders kopieert

namespace internal {
// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if
// appropriate
template<typename Target, typename Head, typename... Tail>
void AppendNoReserve(Target* target, Head&& head, Tail&&... tail) {
    // Currently, require each homogenous inputs. If there is demand, we could probably implement a
    // version that outputs a vector whose value_type is the common_type of all the containers
    // passed to it, and call it ConvertingConcatenate.
    static_assert(
            std::is_same_v<
                    typename std::decay_t<Target>::value_type,
                    typename std::decay_t<Head>::value_type>,
            "Concatenate requires each container passed to it to have the same value_type");
    if constexpr (std::is_lvalue_reference_v<Head>) {
        std::copy(head.begin(), head.end(), std::back_inserter(*target));
    } else {
        std::move(head.begin(), head.end(), std::back_inserter(*target));
    }
    if constexpr (sizeof...(Tail) > 0) {
        AppendNoReserve(target, std::forward<Tail>(tail)...);
    }
}
template<typename Head, typename... Tail>
size_t TotalSize(const Head& head, const Tail&... tail) {
    if constexpr (sizeof...(Tail) > 0) {
        return head.size() + TotalSize(tail...);
    } else {
        return head.size();
    }
}
}  // namespace internal
/// Concatenate the provided containers into a single vector. Moves from rvalue references, copies
/// otherwise.
template<typename Head, typename... Tail>
auto Concatenate(Head&& head, Tail&&... tail) {
    size_t totalSize = internal::TotalSize(head, tail...);
    std::vector<typename std::decay_t<Head>::value_type> result;
    result.reserve(totalSize);
    internal::AppendNoReserve(&result, std::forward<Head>(head), std::forward<Tail>(tail)...);
    return result;
}

Antwoord 20

Deze oplossing kan een beetje ingewikkeld zijn, maar boost-rangeheeft ook enkele andere leuke dingen te bieden.

#include <iostream>
#include <vector>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
    std::vector<int> a = { 1,2,3 };
    std::vector<int> b = { 4,5,6 };
    boost::copy(b, std::back_inserter(a));
    for (auto& iter : a) {
        std::cout << iter << " ";
    }
    return EXIT_SUCCESS;
}

Vaak is het de bedoeling om vector aen bte combineren door er gewoon een bewerking over te doen. In dit geval is er de belachelijk eenvoudige join-functie.

#include <iostream>
#include <vector>
#include <boost/range/join.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
    std::vector<int> a = { 1,2,3 };
    std::vector<int> b = { 4,5,6 };
    std::vector<int> c = { 7,8,9 };
    // Just creates an iterator
    for (auto& iter : boost::join(a, boost::join(b, c))) {
        std::cout << iter << " ";
    }
    std::cout << "\n";
    // Can also be used to create a copy
    std::vector<int> d;
    boost::copy(boost::join(a, boost::join(b, c)), std::back_inserter(d));
    for (auto& iter : d) {
        std::cout << iter << " ";
    }
    return EXIT_SUCCESS;
}

Voor grote vectoren kan dit een voordeel zijn, omdat er niet wordt gekopieerd. Het kan ook worden gebruikt voor het gemakkelijk kopiëren van een generalisatie naar meer dan één container.

Om de een of andere reden gaat er niets boven boost::join(a,b,c), wat redelijk zou kunnen zijn.


Antwoord 21

Voor containers die push_backbieden (string, vector, deque, …):

std::copy(std::begin(input), std::end(input), std::back_inserter(output))

en

voor containers die insertbieden (kaarten, sets):

std::copy(std::begin(input), std::end(input), std::inserter(output, output.end()))


Antwoord 22

Als u op zoek bent naar een manier om een vector aan een andere toe te voegen na het maken, vector::insertis de beste keuze, zoals al meerdere keren is beantwoord, bijvoorbeeld:

vector<int> first = {13};
const vector<int> second = {42};
first.insert(first.end(), second.cbegin(), second.cend());

Helaas is er geen manier om een const vector<int>te construeren, zoals hierboven moet je construeren en vervolgens insert.


Als u eigenlijk op zoek bent naar een container voor de aaneenschakeling van deze twee vector<int>en, is er misschien iets beters voor u beschikbaar, als:

  1. Uw vectorbevat primitieven
  2. Uw ingesloten primitieven zijn 32-bits of kleiner
  3. U wilt een constcontainer

Als het bovenstaande allemaal waar is, raad ik aan om de basic_stringdie char_typeis, komt overeen met de grootte van de primitief in je vector. U moet een static_assertin uw code opnemen om valideer deze maten consistent blijven:

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

Met deze instelling waar kun je gewoon het volgende doen:

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

Voor meer informatie over de verschillen tussen stringen vectorkun je hier kijken: https://stackoverflow.com/a/35558008/2642059

Voor een live voorbeeld van deze code kun je hier kijken: http://ideone.com/7Iww3I


Antwoord 23

U kunt dit doen met vooraf geïmplementeerde STL-algoritmen met behulp van een sjabloon voor gebruik van een polymorf type.

#include <iostream>
#include <vector>
#include <algorithm>
template<typename T>
void concat(std::vector<T>& valuesa, std::vector<T>& valuesb){
     for_each(valuesb.begin(), valuesb.end(), [&](int value){ valuesa.push_back(value);});
}
int main()
{
    std::vector<int> values_p={1,2,3,4,5};
    std::vector<int> values_s={6,7};
   concat(values_p, values_s);
    for(auto& it : values_p){
        std::cout<<it<<std::endl;
    }
    return 0;
}

U kunt de tweede vector wissen als u deze niet verder wilt gebruiken (clear()-methode).


Antwoord 24

Samenvoeg twee std::vector-smet forlussen in één std::vector.

   std::vector <int> v1 {1, 2, 3}; //declare vector1
    std::vector <int> v2 {4, 5}; //declare vector2
    std::vector <int> suma; //declare vector suma
    for(int i = 0; i < v1.size(); i++) //for loop 1
    {
         suma.push_back(v1[i]);
    }
    for(int i = 0; i< v2.size(); i++) //for loop 2
    {
         suma.push_back(v2[i]);
    }
    for(int i = 0; i < suma.size(); i++) //for loop 3-output
    {
         std::cout << suma[i];
    }

Antwoord 25

Probeer, maak twee vectoren en voeg tweede vector toe aan de eerste vector,
Code:

std::vector<int> v1{1,2,3};
std::vector<int> v2{4,5};
for(int i = 0; i<v2.size();i++)
{
     v1.push_back(v2[i]);
}

V1: 1,2,3.

Beschrijving:

Terwijl ik geen V2-formaat, duw het element, index I in V1-vector.


Antwoord 26

Om eerlijk te zijn, kunt u twee vectoren snel aansluiten door elementen van twee vectoren naar de andere te kopiëren of alleen een van de twee vectoren toe te voegen!. Het hangt af van uw doel.

Methode 1: Nieuwe vector toewijzen met de grootte is de som van de grootte van twee originele vectoren.

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

Methode 2: Bevestig Vector A door elementen van vector B toe te voegen / in te voegen.

// 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());

Other episodes