Concatenating two std::vectors
如何连接两个
1 | vector1.insert( vector1.end(), vector2.begin(), vector2.end() ); |
如果您正在使用C++ 11,并且希望移动元素而不是仅仅复制它们,则可以使用EDCOX1与0(插入)(或复制)一起使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #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," ") ); return 0; } |
对于带有ints的示例,这不会更有效,因为移动它们并不比复制它们更有效,但是对于具有优化移动的数据结构,它可以避免复制不必要的状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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的元素将处于未定义但可安全销毁的状态,并且其以前的元素将在末尾直接转移到dest的新元素。
我将使用insert函数,比如:
1 2 3 | vector<int> a, b; //fill with data b.insert(b.end(), a.begin(), a.end()); |
或者你可以使用:
1 | std::copy(source.begin(), source.end(), std::back_inserter(destination)); |
如果两个向量不包含完全相同的类型,则此模式非常有用,因为您可以使用某些内容而不是std::back_inserter从一种类型转换为另一种类型。
用C++ 11,我更喜欢追加向量B到A:
1 | std::move(b.begin(), b.end(), std::back_inserter(a)); |
当
这是来自
1 2 3 4 | std::vector<int> first; std::vector<int> second; first.insert(first.end(), second.begin(), second.end()); |
我喜欢前面提到的那种:
1 | a.insert(a.end(), b.begin(), b.end()); |
但是如果使用C++ 11,则有一种更通用的方式:
1 | a.insert(std::end(a), std::begin(b), std::end(b)); |
此外,这不是问题的一部分,但建议在附加之前使用
所以基本上你需要的是:
1 2 3 4 5 6 | 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::insert
1 | v1.insert(v1.end(), v2.begin(), v2.end()); |
对于范围v3,您可能有一个延迟的连接:
1 | ranges::view::concat(v1, v2) |
演示。
连接的一般性能提升是检查向量的大小。并将较小的和较大的合并/插入。
1 2 3 4 5 6 | //vector<int> v1,v2; if(v1.size()>v2.size()){ v1.insert(v1.end(),v2.begin(),v2.end()); }else{ v1.insert(v2.end(),v1.begin(),v1.end()); } |
如果您对强异常保证感兴趣(当复制构造函数可以抛出异常时):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; } } |
如果向量元素的move构造器可以抛出(虽然不太可能,但仍然如此),那么一般来说,具有强保证的类似
将此文件添加到头文件:
1 2 3 4 5 6 | 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; } |
用这种方法:
1 2 3 4 5 6 7 8 | 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]
1 2 3 | vector<int> v1 = {1, 2, 3, 4, 5}; vector<int> v2 = {11, 12, 13, 14, 15}; copy(v2.begin(), v2.end(), back_inserter(v1)); |
这是一个使用C++ 11移动语义的通用解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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); } |
注意这与
这个解决方案可能有点复杂,但是
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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; } |
通常,我们的目的是将矢量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #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 <<" "; // 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; } |
对于大向量,这可能是一个优势,因为没有复制。它还可以用于将一个通用化轻松复制到多个容器中。
由于某种原因,没有什么能像
您可以为+运算符准备自己的模板:
1 2 3 4 5 6 7 | 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; } |
接下来-只需使用+:
1 2 3 4 5 | vector<int> a{1, 2, 3, 4}; vector<int> b{5, 6, 7, 8}; for (auto x: a + b) cout << x <<""; cout << endl; |
这个例子给出了输出:
1 | <blockquote>1 2 3 4 5 6 7 8</blockquote> |
老实说,您可以通过将元素从两个向量复制到另一个向量来快速连接两个向量,或者只附加两个向量中的一个!这取决于你的目标。
方法1:指定新的向量,其大小是两个原始向量大小的和。
1 2 3 | 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 |
方法2:通过添加/插入向量B的元素来附加向量A。
1 2 | // 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()); |
如果您要寻找的是在创建后将向量附加到另一个向量的方法,那么
1 2 3 4 | vector<int> first = {13}; const vector<int> second = {42}; first.insert(first.end(), second.cbegin(), second.cend()); |
遗憾的是,没有办法构建一个
如果您实际需要的是一个容器来容纳这两个
如果以上都是正确的,我建议使用
1 | static_assert(sizeof(char32_t) == sizeof(int)); |
有了这一点,你就可以做到:
1 | const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend()); |
有关
有关此代码的实况示例,请参阅:http://ideone.com/7iw3i