Related
How do I concatenate two std::vectors?
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
If you are using C++11, and wish to move the elements rather than merely copying them, you can use std::move_iterator along with insert (or copy):
#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;
}
This will not be more efficient for the example with ints, since moving them is no more efficient than copying them, but for a data structure with optimized moves, it can avoid copying unnecessary state:
#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;
}
After the move, src's element is left in an undefined but safe-to-destruct state, and its former elements were transfered directly to dest's new element at the end.
I would use the insert function, something like:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
Or you could use:
std::copy(source.begin(), source.end(), std::back_inserter(destination));
This pattern is useful if the two vectors don't contain exactly the same type of thing, because you can use something instead of std::back_inserter to convert from one type to the other.
With C++11, I'd prefer following to append vector b to a:
std::move(b.begin(), b.end(), std::back_inserter(a));
when a and b are not overlapped, and b is not going to be used anymore.
This is std::move from <algorithm>, not the usual std::move from <utility>.
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
I prefer one that is already mentioned:
a.insert(a.end(), b.begin(), b.end());
But if you use C++11, there is one more generic way:
a.insert(std::end(a), std::begin(b), std::end(b));
Also, not part of a question, but it is advisable to use reserve before appending for better performance. And if you are concatenating vector with itself, without reserving it fails, so you always should reserve.
So basically what you need:
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());
}
With range v3, you may have a lazy concatenation:
ranges::view::concat(v1, v2)
Demo.
A general performance boost for concatenate is to check the size of the vectors. And merge/insert the smaller one with the larger one.
//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());
}
If you want to be able to concatenate vectors concisely, you could overload the += operator.
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;
}
Then you can call it like this:
vector1 += vector2;
There is an algorithm std::merge from C++17, which is very easy to use when the input vectors are sorted,
Below is the example:
#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;
}
You should use vector::insert
v1.insert(v1.end(), v2.begin(), v2.end());
If you are interested in strong exception guarantee (when copy constructor can throw an exception):
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;
}
}
Similar append_move with strong guarantee can't be implemented in general if vector element's move constructor can throw (which is unlikely but still).
If your goal is simply to iterate over the range of values for read-only purposes, an alternative is to wrap both vectors around a proxy (O(1)) instead of copying them (O(n)), so they are promptly seen as a single, contiguous one.
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
Refer to https://stackoverflow.com/a/55838758/2379625 for more details, including the 'VecProxy' implementation as well as pros & cons.
Add this one to your header file:
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;
}
and use it this way:
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 will contain [1,2,62]
Using C++20 you can get rid of begin() and end() with ranges.
#include <ranges>
std::ranges::copy(vec2, std::back_inserter(vec1));
or if you want to move elements:
std::ranges::move(vec2, std::back_inserter(vec1));
Here's a general purpose solution using C++11 move semantics:
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);
}
Note how this differs from appending to a vector.
You can prepare your own template for + 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;
}
Next thing - just use +:
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
This example gives output:
1 2 3 4 5 6 7 8
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
I've implemented this function which concatenates any number of containers, moving from rvalue-references and copying otherwise
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;
}
This solution might be a bit complicated, but boost-range has also some other nice things to offer.
#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;
}
Often ones intention is to combine vector a and b just iterate over it doing some operation. In this case, there is the ridiculous simple join function.
#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;
}
For large vectors this might be an advantage, as there is no copying. It can be also used for copying an generalizes easily to more than one container.
For some reason there is nothing like boost::join(a,b,c), which could be reasonable.
For containers which offer push_back (string, vector, deque, ...):
std::copy(std::begin(input), std::end(input), std::back_inserter(output))
and
for containers which offer insert (maps, sets):
std::copy(std::begin(input), std::end(input), std::inserter(output, output.end()))
If what you're looking for is a way to append a vector to another after creation, vector::insert is your best bet, as has been answered several times, for example:
vector<int> first = {13};
const vector<int> second = {42};
first.insert(first.end(), second.cbegin(), second.cend());
Sadly there's no way to construct a const vector<int>, 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 vector<int>s, there may be something better available to you, if:
Your vector contains primitives
Your contained primitives are of size 32-bit or smaller
You want a const container
If the above are all true, I'd suggest using the basic_string who's char_type matches the size of the primitive contained in your vector. You should include a static_assert in your code to validate these sizes stay consistent:
static_assert(sizeof(char32_t) == sizeof(int));
With this holding true you can just do:
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
You can do it with pre-implemented STL algorithms using a template for a polymorphic type use.
#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;
}
You can clear the second vector if you don't want to use it further (clear() method).
Concatenate two std::vector-s with for loop in one 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];
}
To be honest, you could fast concatenate two vectors by copy elements from two vectors into the other one or just only append one of two vectors!. It depends on your aim.
Method 1: Assign new vector with its size is the sum of two original vectors' size.
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
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());
Try, create two vectors and add second vector to first 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.
Description:
While i int not v2 size, push back element , index i in v1 vector.
I'm using multitreading and want to merge the results. For example:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
I want AB to have to contents of A and the contents of B in that order. What's the most efficient way of doing something like this?
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
This is precisely what the member function std::vector::insert is for
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
Depends on whether you really need to physically concatenate the two vectors or you want to give the appearance of concatenation of the sake of iteration. The boost::join function
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
will give you this.
std::vector<int> v0;
v0.push_back(1);
v0.push_back(2);
v0.push_back(3);
std::vector<int> v1;
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
...
BOOST_FOREACH(const int & i, boost::join(v0, v1)){
cout << i << endl;
}
should give you
1
2
3
4
5
6
Note boost::join does not copy the two vectors into a new container
but generates a pair of iterators (range) that cover the span of
both containers. There will be some performance overhead but maybe
less that copying all the data to a new container first.
In the direction of Bradgonesurfing's answer, many times one doesn't really need to concatenate two vectors (O(n)), but instead just work with them as if they were concatenated (O(1)). If this is your case, it can be done without the need of Boost libraries.
The trick is to create a vector proxy: a wrapper class which manipulates references to both vectors, externally seen as a single, contiguous one.
USAGE
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1). No copies performed.
for (size_t i = 0; i < AB.size(); ++i)
std::cout << AB[i] << " "; // 1 2 3 4 5 10 20 30
IMPLEMENTATION
template <class T>
class VecProxy {
private:
std::vector<T>& v1, v2;
public:
VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {}
const T& operator[](const size_t& i) const;
const size_t size() const;
};
template <class T>
const T& VecProxy<T>::operator[](const size_t& i) const{
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
template <class T>
const size_t VecProxy<T>::size() const { return v1.size() + v2.size(); };
MAIN BENEFIT
It's O(1) (constant time) to create it, and with minimal extra memory allocation.
SOME STUFF TO CONSIDER
You should only go for it if you really know what you're doing when dealing with references. This solution is intended for the specific purpose of the question made, for which it works pretty well. To employ it in any other context may lead to unexpected behavior if you are not sure on how references work.
In this example, AB does not provide a non-const
access operator ([ ]). Feel free to include it, but keep in mind: since AB contains references, to assign it
values will also affect the original elements within A and/or B. Whether or not this is a
desirable feature, it's an application-specific question one should
carefully consider.
Any changes directly made to either A or B (like assigning values,
sorting, etc.) will also "modify" AB. This is not necessarily bad
(actually, it can be very handy: AB does never need to be explicitly
updated to keep itself synchronized to both A and B), but it's
certainly a behavior one must be aware of. Important exception: to resize A and/or B to sth bigger may lead these to be reallocated in memory (for the need of contiguous space), and this would in turn invalidate AB.
Because every access to an element is preceded by a test (namely, "i
< v1.size()"), VecProxy access time, although constant, is also
a bit slower than that of vectors.
This approach can be generalized to n vectors. I haven't tried, but
it shouldn't be a big deal.
Based on Kiril V. Lyadvinsky answer, I made a new version. This snippet use template and overloading. With it, you can write vector3 = vector1 + vector2 and vector4 += vector3. Hope it can help.
template <typename T>
std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B)
{
std::vector<T> AB;
AB.reserve(A.size() + B.size()); // preallocate memory
AB.insert(AB.end(), A.begin(), A.end()); // add A;
AB.insert(AB.end(), B.begin(), B.end()); // add B;
return AB;
}
template <typename T>
std::vector<T> &operator+=(std::vector<T> &A, const std::vector<T> &B)
{
A.reserve(A.size() + B.size()); // preallocate memory without erase original data
A.insert(A.end(), B.begin(), B.end()); // add B;
return A; // here A could be named AB
}
One more simple variant which was not yet mentioned:
copy(A.begin(),A.end(),std::back_inserter(AB));
copy(B.begin(),B.end(),std::back_inserter(AB));
And using merge algorithm:
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
template<template<typename, typename...> class Container, class T>
std::string toString(const Container<T>& v)
{
std::stringstream ss;
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(ss, ""));
return ss.str();
};
int main()
{
std::vector<int> A(10);
std::vector<int> B(5); //zero filled
std::vector<int> AB(15);
std::for_each(A.begin(), A.end(),
[](int& f)->void
{
f = rand() % 100;
});
std::cout << "before merge: " << toString(A) << "\n";
std::cout << "before merge: " << toString(B) << "\n";
merge(B.begin(),B.end(), begin(A), end(A), AB.begin(), [](int&,int&)->bool {});
std::cout << "after merge: " << toString(AB) << "\n";
return 1;
}
All the solutions are correct, but I found it easier just write a function to implement this. like this:
template <class T1, class T2>
void ContainerInsert(T1 t1, T2 t2)
{
t1->insert(t1->end(), t2->begin(), t2->end());
}
That way you can avoid the temporary placement like this:
ContainerInsert(vec, GetSomeVector());
For this use case, if you know beforehand the number of results each thread produces, you could preallocate AB and pass a std::span to each thread. This way the concatenation need not be done. Example:
std::vector<int> AB(total_number_of_results, 0);
std::size_t chunk_length = …;
std::size_t chunk2_start = chunk_length;
std::size_t chunk3_start = 2 * chunk_length; // If needed
…
// Pass these to the worker threads.
std::span<int> A(AB.data(), chunk_length);
std::span<int> B(AB.data() + chunk2_start, chunk_length);
…
My answer is based on Mr.Ronald Souza's original solution. In addition to his original solution, I've written a vector proxy that supports iterators too!
short description for people who are not aware of the context of the original solution: the joined_vector template class (i.e the vector proxy)takes two references of two vectors as constructor arguments, it then treats them as one contiguous vector. My implementation also supports a forward-iterator.
USAGE:
int main()
{
std::vector<int> a1;
std::vector<int> a2;
joined_vector<std::vector<int>> jv(a1,a2);
for (int i = 0; i < 5; i++)
a1.push_back(i);
for (int i = 5; i <=10; i++)
a2.push_back(i);
for (auto e : jv)
std::cout << e<<"\n";
for (int i = 0; i < jv.size(); i++)
std::cout << jv[i] << "\n";
return 0;
}
IMPLEMENTATION:
template<typename _vec>
class joined_vector
{
_vec& m_vec1;
_vec& m_vec2;
public:
struct Iterator
{
typedef typename _vec::iterator::value_type type_value;
typedef typename _vec::iterator::value_type* pointer;
typedef typename _vec::iterator::value_type& reference;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
_vec* m_vec1;
_vec* m_vec2;
Iterator(pointer ptr) :m_ptr(ptr)
{
}
Iterator operator++()
{
if (m_vec1->size() > 0 && m_ptr == &(*m_vec1)[m_vec1->size() - 1] && m_vec2->size() != 0)
m_ptr = &(*m_vec2)[0];
else
++m_ptr;
return m_ptr;
}
Iterator operator++(int)
{
pointer curr = m_ptr;
if (m_vec1->size() > 0 && m_ptr == &(*m_vec1)[m_vec1->size() - 1] && m_vec2->size() != 0)
m_ptr = &(*m_vec2)[0];
else
++m_ptr;
return curr;
}
reference operator *()
{
return *m_ptr;
}
pointer operator ->()
{
return m_ptr;
}
friend bool operator == (Iterator& itr1, Iterator& itr2)
{
return itr1.m_ptr == itr2.m_ptr;
}
friend bool operator != (Iterator& itr1, Iterator& itr2)
{
return itr1.m_ptr != itr2.m_ptr;
}
private:
pointer m_ptr;
};
joined_vector(_vec& vec1, _vec& vec2) :m_vec1(vec1), m_vec2(vec2)
{
}
Iterator begin()
{
//checkes if m_vec1 is empty and gets the first elemet's address,
//if it's empty then it get's the first address of the second vector m_vec2
//if both of them are empty then nullptr is returned as the first pointer
Iterator itr_beg((m_vec1.size() != 0) ? &m_vec1[0] : ((m_vec2.size() != 0) ? &m_vec2[0] : nullptr));
itr_beg.m_vec1 = &m_vec1;
itr_beg.m_vec2 = &m_vec2;
return itr_beg;
}
Iterator end()
{
//check if m_vec2 is empty and get the last address of that vector
//if the second vector is empty then the m_vec1's vector/the first vector's last element's address is taken
//if both of them are empty then a null pointer is returned as the end pointer
typename _vec::value_type* p = ((m_vec2.size() != 0) ? &m_vec2[m_vec2.size() - 1] : ((m_vec1.size()) != 0 ? &m_vec1[m_vec1.size() - 1] : nullptr));
Iterator itr_beg(p != nullptr ? p + 1 : nullptr);
itr_beg.m_vec1 = &m_vec1;
itr_beg.m_vec2 = &m_vec2;
return itr_beg;
}
typename _vec::value_type& operator [](int i)
{
if (i < m_vec1.size())
return m_vec1[i];
else
return m_vec2[i - m_vec1.size()];
}
size_t size()
{
return m_vec1.size() + m_vec2.size();
}
};
If your vectors are sorted*, check out set_union from <algorithm>.
set_union(A.begin(), A.end(), B.begin(), B.end(), AB.begin());
There's a more thorough example in the link.
I have a vector<std::unique_ptr<X>> and a vector<const X*> that contain the same set of pointers, but in a different order. I want to have the vector of unique pointers be ordered exactly like the vector of const pointers.
One way I could do it is like this:
vector<std::unique_ptr<X>> uniq_ptrs;
vector<const X*> const_ptrs;
vector<std::unique_ptr<X>> tmp(uniq_ptrs.size());
hash_map<const X*, int> indices;
for (int i = 0; i < const_ptrs->size(); ++i) {
indices[const_ptrs[i]] = i;
}
for (std::unique_ptr<X>& uniq_ptr : uniq_ptrs) {
tmp[indices[uniq_ptr.get()]].swap(uniq_ptr);
}
uniq_ptrs.swap(tmp)
an in-place version, still with hash_map:
vector<const X*> const_ptrs;
hash_map<const X*, int> indices;
for (int i = 0; i < const_ptrs.size(); ++i) {
indices[const_ptrs[i]] = i;
}
for (int i = 0; i < const_ptrs.size(); ++i) {
std::swap(uniq_ptrs[i], uniq_ptrs[indices[const_ptrs[i]]]);
}
But I hope there is a nicer way that doesn't involve a temporary vector a hash map and two passes over the data.
Since the const_ptrs contains the same pointers as the uniq_ptrs, there is no need to use the latter at all, and no need for a temporary either. However, you must be careful not to delete the objects.
// release the unique_ptrs of their ownership
for(auto&x : uniq_ptrs)
x.release();
// fill the array with the pointers in another order
uniq_ptrs.clear();
for(auto x : const_ptrs)
uniq_ptrs.emplace_back(const_cast<X*>(x)); // const_cast okay here
If performance were no issue:
auto idx_of = [&](X const* p) {
return std::distance(begin(const_ptrs), std::find(begin(const_ptrs), end(const_ptrs), p));
};
std::sort(begin(uniq_ptrs), end(uniq_ptrs), [&](std::unique_ptr<X> const& a, std::unique_ptr<X> const& b) {
return idx_of(a.get()) < idx_of(b.get());
});
If performance is a concern, use your intermediate map:
hash_map<const X*, int> indices;
for (auto i = 0u; i < const_ptrs.size(); ++i) {
indices[const_ptrs[i]] = i;
}
std::sort(begin(uniq_ptrs), end(uniq_ptrs), [&](std::unique_ptr<X> const& a, std::unique_ptr<X> const& b) {
return indices[ a.get() ] < indices[ b.get() ];
});
---If you're absolutely sure about the sets of pointers matching, you could cheat and create completely new unique_ptrs on the fly.--- Hmm won't work because of the const, like you said.
Update Just drop the const, if the performance is leading here. If you know the objects aren't actually const, you can employ the evil const_cast<>
See all three approaches: Live on Coliru
#include <unordered_map>
#include <algorithm>
#include <memory>
#include <vector>
#include <cassert>
template <typename K, typename V>
using hash_map = std::unordered_map<K,V>;
struct X{};
int main()
{
std::vector<std::unique_ptr<X>> uniq_ptrs;
std::vector<const X*> const_ptrs;
// naive approach, no performance worries
auto idx_of = [&](X const* p) {
return std::distance(begin(const_ptrs), std::find(begin(const_ptrs), end(const_ptrs), p));
};
std::sort(begin(uniq_ptrs), end(uniq_ptrs), [&](std::unique_ptr<X> const& a, std::unique_ptr<X> const& b) {
return idx_of(a.get()) < idx_of(b.get());
});
// less naive approach, no performance worries
hash_map<const X*, int> indices;
for (auto i = 0u; i < const_ptrs.size(); ++i) {
indices[const_ptrs[i]] = i;
}
std::sort(begin(uniq_ptrs), end(uniq_ptrs), [&](std::unique_ptr<X> const& a, std::unique_ptr<X> const& b) {
return indices[ a.get() ] < indices[ b.get() ];
});
// cheating! only not UB if you know the objects aren't "physically" const
assert(const_ptrs.size() == uniq_ptrs.size());
for (auto i = 0u; i < const_ptrs.size(); ++i) {
uniq_ptrs[i].release();
uniq_ptrs[i].reset(const_cast<X*>(const_ptrs[i]));
}
}
Apologies for the title, I was struggling to come up with one.
I asked a question on here Here and I'm trying to advanced with it. I have a struct:
namespace Complex {
typedef struct complex_t {
double re;
double im;
} complex;
}
And I wish to push back either an array or a vector to a 1D vector of complex, as follows:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
for(auto i=begin; (i != end); i++)
{
vals12[i].re = *i;
}
return vals12;
}
And get the following error:
no viable overloaded operator[] for type 'vector<Complex::complex>'
vals12[i].re = *i;
Now note if I do the following:
vals12[0].re = 10;
Will work, but, when using arrays it throws this error and I cannot understand why this is. My only thought is that it could be due to the fact I'm passing an array through rather than a vector. Here is the full code:
#include <iostream>
#include <vector>
#include "complex.h"
using namespace std;
//using namespace Complex;
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
for(auto i=begin; (i != end); i++)
{
vals12[i].re = *i;
}
return vals12;
}
class Value
{
public:
template <typename Fred>
Value(Fred begin, Fred end)
{
vector<Complex::complex> vec = convertToComplex(begin, end);
}
};
int main()
{
double vals[] = {10, 23, 23, 34, 354};
Value v(std::begin(vals), std::end(vals));
}
Does anyone have any ideas to where I am going wrong? I really hope someone can help me.
Update:
template<typename Iterator>
vector<Complex::complex> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex> vals12(10);
size_t index = 0;
for(auto i=begin; (i != end); i++)
{
complex c;
c.re = *i;
c.im = *i;
vals12[index].re = c.re;
vals12[index].im = c.im;
index++;
}
return vals12;
}
Error:
error: assigning to 'double *' from incompatible type 'double'; remove *
c.re = *i;
When you declare i as auto in the for initializer it takes on the type of begin which in this case is a pointer to double. You are then attempting to pass that pointer the index operator of std::vector (although indirectly via [i]).
You will need to use an additional variable to act as the index.
size_t index = 0;
for(auto i=begin; (i != end); i++)
{
vals12[index++].re = *i;
}
Other answers have explained why your code doesn't compile. You actually want a transform algorithm:
namespace Complex {
struct complex_t {
double re;
double im;
};
}
template<typename Iterator>
vector<Complex::complex_t> convertToComplex(Iterator begin, Iterator end)
{
vector<Complex::complex_t> vals12;
std::transform(begin, end, std::back_inserter(vals12),
[](const double& d ){ return Complex::complex_t{d,0}; });
return vals12;
}
Note that i is an Iterator. However, operator[] expects an int for the index into the vector. You have at least two solutions:
Create a counter for the index into the vector.
Create an empty vector and use push_back().
I'm using multitreading and want to merge the results. For example:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
I want AB to have to contents of A and the contents of B in that order. What's the most efficient way of doing something like this?
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
This is precisely what the member function std::vector::insert is for
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
Depends on whether you really need to physically concatenate the two vectors or you want to give the appearance of concatenation of the sake of iteration. The boost::join function
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
will give you this.
std::vector<int> v0;
v0.push_back(1);
v0.push_back(2);
v0.push_back(3);
std::vector<int> v1;
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
...
BOOST_FOREACH(const int & i, boost::join(v0, v1)){
cout << i << endl;
}
should give you
1
2
3
4
5
6
Note boost::join does not copy the two vectors into a new container
but generates a pair of iterators (range) that cover the span of
both containers. There will be some performance overhead but maybe
less that copying all the data to a new container first.
In the direction of Bradgonesurfing's answer, many times one doesn't really need to concatenate two vectors (O(n)), but instead just work with them as if they were concatenated (O(1)). If this is your case, it can be done without the need of Boost libraries.
The trick is to create a vector proxy: a wrapper class which manipulates references to both vectors, externally seen as a single, contiguous one.
USAGE
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1). No copies performed.
for (size_t i = 0; i < AB.size(); ++i)
std::cout << AB[i] << " "; // 1 2 3 4 5 10 20 30
IMPLEMENTATION
template <class T>
class VecProxy {
private:
std::vector<T>& v1, v2;
public:
VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {}
const T& operator[](const size_t& i) const;
const size_t size() const;
};
template <class T>
const T& VecProxy<T>::operator[](const size_t& i) const{
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
template <class T>
const size_t VecProxy<T>::size() const { return v1.size() + v2.size(); };
MAIN BENEFIT
It's O(1) (constant time) to create it, and with minimal extra memory allocation.
SOME STUFF TO CONSIDER
You should only go for it if you really know what you're doing when dealing with references. This solution is intended for the specific purpose of the question made, for which it works pretty well. To employ it in any other context may lead to unexpected behavior if you are not sure on how references work.
In this example, AB does not provide a non-const
access operator ([ ]). Feel free to include it, but keep in mind: since AB contains references, to assign it
values will also affect the original elements within A and/or B. Whether or not this is a
desirable feature, it's an application-specific question one should
carefully consider.
Any changes directly made to either A or B (like assigning values,
sorting, etc.) will also "modify" AB. This is not necessarily bad
(actually, it can be very handy: AB does never need to be explicitly
updated to keep itself synchronized to both A and B), but it's
certainly a behavior one must be aware of. Important exception: to resize A and/or B to sth bigger may lead these to be reallocated in memory (for the need of contiguous space), and this would in turn invalidate AB.
Because every access to an element is preceded by a test (namely, "i
< v1.size()"), VecProxy access time, although constant, is also
a bit slower than that of vectors.
This approach can be generalized to n vectors. I haven't tried, but
it shouldn't be a big deal.
Based on Kiril V. Lyadvinsky answer, I made a new version. This snippet use template and overloading. With it, you can write vector3 = vector1 + vector2 and vector4 += vector3. Hope it can help.
template <typename T>
std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B)
{
std::vector<T> AB;
AB.reserve(A.size() + B.size()); // preallocate memory
AB.insert(AB.end(), A.begin(), A.end()); // add A;
AB.insert(AB.end(), B.begin(), B.end()); // add B;
return AB;
}
template <typename T>
std::vector<T> &operator+=(std::vector<T> &A, const std::vector<T> &B)
{
A.reserve(A.size() + B.size()); // preallocate memory without erase original data
A.insert(A.end(), B.begin(), B.end()); // add B;
return A; // here A could be named AB
}
One more simple variant which was not yet mentioned:
copy(A.begin(),A.end(),std::back_inserter(AB));
copy(B.begin(),B.end(),std::back_inserter(AB));
And using merge algorithm:
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
template<template<typename, typename...> class Container, class T>
std::string toString(const Container<T>& v)
{
std::stringstream ss;
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(ss, ""));
return ss.str();
};
int main()
{
std::vector<int> A(10);
std::vector<int> B(5); //zero filled
std::vector<int> AB(15);
std::for_each(A.begin(), A.end(),
[](int& f)->void
{
f = rand() % 100;
});
std::cout << "before merge: " << toString(A) << "\n";
std::cout << "before merge: " << toString(B) << "\n";
merge(B.begin(),B.end(), begin(A), end(A), AB.begin(), [](int&,int&)->bool {});
std::cout << "after merge: " << toString(AB) << "\n";
return 1;
}
All the solutions are correct, but I found it easier just write a function to implement this. like this:
template <class T1, class T2>
void ContainerInsert(T1 t1, T2 t2)
{
t1->insert(t1->end(), t2->begin(), t2->end());
}
That way you can avoid the temporary placement like this:
ContainerInsert(vec, GetSomeVector());
For this use case, if you know beforehand the number of results each thread produces, you could preallocate AB and pass a std::span to each thread. This way the concatenation need not be done. Example:
std::vector<int> AB(total_number_of_results, 0);
std::size_t chunk_length = …;
std::size_t chunk2_start = chunk_length;
std::size_t chunk3_start = 2 * chunk_length; // If needed
…
// Pass these to the worker threads.
std::span<int> A(AB.data(), chunk_length);
std::span<int> B(AB.data() + chunk2_start, chunk_length);
…
My answer is based on Mr.Ronald Souza's original solution. In addition to his original solution, I've written a vector proxy that supports iterators too!
short description for people who are not aware of the context of the original solution: the joined_vector template class (i.e the vector proxy)takes two references of two vectors as constructor arguments, it then treats them as one contiguous vector. My implementation also supports a forward-iterator.
USAGE:
int main()
{
std::vector<int> a1;
std::vector<int> a2;
joined_vector<std::vector<int>> jv(a1,a2);
for (int i = 0; i < 5; i++)
a1.push_back(i);
for (int i = 5; i <=10; i++)
a2.push_back(i);
for (auto e : jv)
std::cout << e<<"\n";
for (int i = 0; i < jv.size(); i++)
std::cout << jv[i] << "\n";
return 0;
}
IMPLEMENTATION:
template<typename _vec>
class joined_vector
{
_vec& m_vec1;
_vec& m_vec2;
public:
struct Iterator
{
typedef typename _vec::iterator::value_type type_value;
typedef typename _vec::iterator::value_type* pointer;
typedef typename _vec::iterator::value_type& reference;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
_vec* m_vec1;
_vec* m_vec2;
Iterator(pointer ptr) :m_ptr(ptr)
{
}
Iterator operator++()
{
if (m_vec1->size() > 0 && m_ptr == &(*m_vec1)[m_vec1->size() - 1] && m_vec2->size() != 0)
m_ptr = &(*m_vec2)[0];
else
++m_ptr;
return m_ptr;
}
Iterator operator++(int)
{
pointer curr = m_ptr;
if (m_vec1->size() > 0 && m_ptr == &(*m_vec1)[m_vec1->size() - 1] && m_vec2->size() != 0)
m_ptr = &(*m_vec2)[0];
else
++m_ptr;
return curr;
}
reference operator *()
{
return *m_ptr;
}
pointer operator ->()
{
return m_ptr;
}
friend bool operator == (Iterator& itr1, Iterator& itr2)
{
return itr1.m_ptr == itr2.m_ptr;
}
friend bool operator != (Iterator& itr1, Iterator& itr2)
{
return itr1.m_ptr != itr2.m_ptr;
}
private:
pointer m_ptr;
};
joined_vector(_vec& vec1, _vec& vec2) :m_vec1(vec1), m_vec2(vec2)
{
}
Iterator begin()
{
//checkes if m_vec1 is empty and gets the first elemet's address,
//if it's empty then it get's the first address of the second vector m_vec2
//if both of them are empty then nullptr is returned as the first pointer
Iterator itr_beg((m_vec1.size() != 0) ? &m_vec1[0] : ((m_vec2.size() != 0) ? &m_vec2[0] : nullptr));
itr_beg.m_vec1 = &m_vec1;
itr_beg.m_vec2 = &m_vec2;
return itr_beg;
}
Iterator end()
{
//check if m_vec2 is empty and get the last address of that vector
//if the second vector is empty then the m_vec1's vector/the first vector's last element's address is taken
//if both of them are empty then a null pointer is returned as the end pointer
typename _vec::value_type* p = ((m_vec2.size() != 0) ? &m_vec2[m_vec2.size() - 1] : ((m_vec1.size()) != 0 ? &m_vec1[m_vec1.size() - 1] : nullptr));
Iterator itr_beg(p != nullptr ? p + 1 : nullptr);
itr_beg.m_vec1 = &m_vec1;
itr_beg.m_vec2 = &m_vec2;
return itr_beg;
}
typename _vec::value_type& operator [](int i)
{
if (i < m_vec1.size())
return m_vec1[i];
else
return m_vec2[i - m_vec1.size()];
}
size_t size()
{
return m_vec1.size() + m_vec2.size();
}
};
If your vectors are sorted*, check out set_union from <algorithm>.
set_union(A.begin(), A.end(), B.begin(), B.end(), AB.begin());
There's a more thorough example in the link.