Concatenating Two Std::Vectors

What is the best way to concatenate two vectors?

AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );

Is there a way to concatenate multiple vectors simply?

If you can use range v3, you can simply do this:

std::vector<std::string> allVec = ranges::view::concat(a, b, c, d);

See demo here.

You can use this with any vector type.

Construction a vector from the concatenation of 2 vectors

No, it's not possible if you require that

  • no helper function is defined, and
  • the resulting vector can be declared const.

Concatenate multiple std::vectors taking duplicates into account in c++17

You can do something like the following.

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
std::vector<int> v1 = {1,2,6}, v2 = {6,8,9}, v3 = {9,8,10}, v4 = {0, 1};

for ( auto p : { &v2, &v3, &v4 } )
{
auto it = std::begin( *p );

if ( v1.back() == p->front() )
{
std::advance( it, 1 );
}

v1.insert( std::end( v1 ), it, std::end( *p ) );
}

for ( const auto &item : v1 )
{
std::cout << item << ' ';
}
std::cout << '\n';

return 0;
}

The program output is

1 2 6 8 9 8 10 0 1

Or you can preliminary reserve enough space in the vector v1. For example

#include <iostream>
#include <vector>
#include <iterator>

int main()
{
std::vector<int> v1 = {1,2,6}, v2 = {6,8,9}, v3 = {9,8,10}, v4 = {0, 1};

std::vector<int>::size_type n = v1.size();
auto last = v1.back();

for ( auto p : { &v2, &v3, &v4 } )
{
n += last == p->front() ? p->size() - 1 : p->size();
last = p->back();
}

v1.reserve( n );

for ( auto p : { &v2, &v3, &v4 } )
{
auto it = std::begin( *p );

if ( v1.back() == p->front() )
{
std::advance( it, 1 );
}

v1.insert( std::end( v1 ), it, std::end( *p ) );
}

for ( const auto &item : v1 )
{
std::cout << item << ' ';
}
std::cout << '\n';

return 0;
}

How to concatenate many std::vectors?

You can do this in C++11:

std::for_each(aVector.begin(), aVector.end(), [&](AClass i){const auto& temp = i.getCoeffs(); coeffs.insert(coeffs.end(), temp.begin(), temp.end());});

C++03 is more difficult because it lacks lambdas and bind.

About as good as you can do is to use copy in your internal loop:

for(std::vector<AClass>::iterator it = aVector.begin(); it != aVector.end(); ++it){
const std::vector<double>& temp = it->getCoeffs();
coeffs.insert(coeffs.end(), temp.begin(), temp.end());
}

These are both essentially the same thing, though you could improve your runtime on both by returning a const std::vector<double>& from getCoeffs.

EDIT:

Arg, just saw you added insert to your question. I thought I was really going to help you out there. As a consolation tip, what you are really asking about here is flattening a std::vector of std::vectors. That has an answer here. But should you have access to boost you should look at: http://www.boost.org/doc/libs/1_57_0/libs/multi_array/doc/reference.html#synopsis

Concatenate 2 STL vectors in constant O(1) time

A vector is not a list, it represents a sequence, but with the additional requirement that elements must be stored in contiguous memory. You cannot just bundle two vectors (whose buffers won't be contiguous) into a single vector without moving objects around.

C++ template function to concatenate both std::vector and std::array types

In general, generic + arbitrary, means templates.

Something like this?

template<class SizedRange1, class SizedRange2>
auto concat(SizedRange1 const& r1, SizedRange2 const& r2) {
std::vector<typename SizedRange1::value_type> ret;
ret.reserve(r1.size() + r2.size());

using std::begin; using std::end;
ret.insert(ret.end(), begin(r1), end(r1));
ret.insert(ret.end(), begin(r2), end(r2));

return ret;
}

EDIT:

The advantage of @康桓瑋's solution (which assumes that you are only interested in concatenating contiguous memory containers as you stated) is that you have a single function and you avoid code bloat.

As you noticed in the comments, the problem with that you can not deduce the element type, which can be anything in principle, so you are back to needing templates anyway.

Fortunately, you can combine the two approaches and reduce the number of functions generated as machine code, in the case that you have many different input containers, which is combinatorial.

template<class T>
std::vector<T>
concat_aux(std::span<const T> x, std::span<const T> y) {
std::vector<T> ret;
ret.reserve(x.size() + y.size());
ret.insert(ret.end(), x.begin(), x.end());
ret.insert(ret.end(), y.begin(), y.end());
return ret;
}

template<class ContinuousRange1, class ContinuousRange2>
auto concat(ContinuousRange1 const& r1, ContinuousRange2 const& r2) {
return concat_aux<typename ContinousRange1::value_type>(r1, r2);
}

The advantage is marginal here, but if the function concat is very complicated this last approach will pay off because it will generate code only for the different types of elements, not the number of containers squared in your instantiating code.



Related Topics



Leave a reply



Submit