连接两个d::向量

如何连接两个std::vector

582227 次浏览

我将使用插入函数,类似于:

vector<int> a, b;//fill with datab.insert(b.end(), a.begin(), a.end());
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
std::vector<int> first;std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());

或者您可以使用:

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

如果两个向量不包含完全相同类型的东西,则此模式很有用,因为您可以使用某些东西而不是std::back_inserter来从一种类型转换为另一种类型。

如果你正在使用C++11,并且希望移动元素而不仅仅是复制它们,你可以使用std::move_iterator和插入(或复制):

#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;}

对于使用int的示例,这不会更有效,因为移动它们并不比复制它们更有效,但对于具有优化移动的数据结构,它可以避免复制不必要的状态:

#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;}

移动后,src的元素处于未定义但可安全销毁的状态,并且它以前的元素在最后直接转移到est的新元素。

如果您对强异常保证感兴趣(当复制构造函数可以抛出异常时):

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;}}

如果向量元素的移动构造函数可以抛出(这不太可能,但仍然),则通常无法实现具有强保证的类似append_move

对于C++11,我更喜欢将向量b附加到a:

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

ab不重叠时,将不再使用b


这是<algorithm>std::move,不是<utility>通常std::move

将此添加到您的头文件中:

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;}

并以这种方式使用它:

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将包含[1,2,62]

如果你正在寻找的是一种在创建后将向量附加到另一个向量的方法,那么vector::insert是你最好的选择,正如已经回答过几次的那样,例如:

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

可悲的是,没有办法构造一个const vector<int>,如上所述,你必须构造然后insert


如果您实际上正在寻找的是一个容器来容纳这两个vector<int>的连接,那么可能会有更好的东西可供您使用,如果:

  1. 您的vector包含原语
  2. 您包含的基元大小为32位或更小
  3. 你想要一个const容器

如果以上都是真的,我建议使用basic_string,谁的char_typevector中包含的基元的大小匹配。你应该在代码中包含static_assert来验证这些大小保持一致:

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

有了这个信念,你可以这样做:

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

有关stringvector之间差异的更多信息,您可以在此处查看:https://stackoverflow.com/a/35558008/2642059

有关此代码的实时示例,您可以在此处查看:http://ideone.com/7Iww3I

我更喜欢已经提到的一个:

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

但是如果你使用C++11,还有一种更通用的方法:

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

此外,这不是问题的一部分,但建议在附加之前使用reserve以获得更好的性能。如果你将向量与自身连接,而不保留它会失败,所以你总是应该reserve


所以基本上你需要什么:

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

老实说,您可以通过将元素从两个向量复制到另一个向量来快速连接两个向量,或者只附加两个向量中的一个!。这取决于您的目标。

方法一:分配新向量,其大小是两个原始向量大小的总和。

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

方法二:通过添加/插入向量B的元素来附加向量A。

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

使用范围v3,您可能会有懒惰的连接:

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

Demo

你应该使用矢量::插入

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

这是一个使用C++11移动语义学的通用解决方案:

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);}

注意这与appending和vector有何不同。

用于连接的普遍性能提升是检查向量的大小。并将较小的与较大的合并/插入。

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

您可以为+运算符准备自己的模板:

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;}

下一步-只需使用+:

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

这个例子给出了输出:

1 2 3 4 5 6 7 8

这个解决方案可能有点复杂,但boost-range也提供了一些其他的好东西。

#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;}

通常人们的意图是组合向量ab只是迭代它做一些操作。在这种情况下,有荒谬的简单join函数。

#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 iteratorfor (auto& iter : boost::join(a, boost::join(b, c))) {std::cout << iter << " ";}std::cout << "\n";// Can also be used to create a copystd::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;}

对于大向量,这可能是一个优势,因为没有复制。它也可以用于将泛化轻松复制到多个容器。

出于某种原因,没有像boost::join(a,b,c)这样的东西,这可能是合理的。

如果您希望能够简洁地连接向量,您可以重载+=运算符。

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;}

你可以这样称呼它:

vector1 += vector2;

我已经实现了这个函数,它连接了任意数量的容器,从右值引用移动,否则复制

namespace internal {
// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if// appropriatetemplate<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;}

有一个算法std::merge来自C++17,当输入向量排序时非常容易使用,

下面是例子:

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

如果您的目标只是为了只读目的而遍历值的范围,那么另一种选择是将两个向量包装在代理(O(1))周围,而不是复制它们(O(n)),因此它们会立即被视为单个连续的向量。

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

有关更多详细信息,请参阅https://stackoverflow.com/a/55838758/2379625,包括“VecProxy”实现以及优缺点。

您可以使用用于多态类型使用的模板使用预实现的STL算法来执行此操作。

#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;}

如果您不想进一步使用它,您可以清除第二个向量(clear()方法)。

将两个std::vector-sfor循环连接在一个std::vector中。

    std::vector <int> v1 {1, 2, 3}; //declare vector1std::vector <int> v2 {4, 5}; //declare vector2std::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];}

尝试创建两个向量并将第二个向量添加到第一个向量,代码:

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。

问题描述

当i int不是v2 size时,返回元素,在v1向量中索引i。

对于提供push_back(string、向量、双端队列…)的容器:

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

对于提供insert(map, set)的容器:

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

使用C++20,您可以摆脱带有范围的开始()和结束()。

#include <ranges>
std::ranges::copy(vec2, std::back_inserter(vec1));

或者如果你想移动元素:

std::ranges::move(vec2, std::back_inserter(vec1));