C++ 连接两个向量的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3177241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the best way to concatenate two vectors?
提问by jmasterx
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 必须按顺序处理 A 的内容和 B 的内容。做这样的事情最有效的方法是什么?
回答by Kirill V. Lyadvinsky
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
回答by Shirik
This is precisely what the member function std::vector::insert
is for
这正是成员函数std::vector::insert
的用途
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
回答by bradgonesurfing
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
取决于您是否真的需要物理连接两个向量,或者您想要为了迭代而提供连接的外观。boost::join 函数
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
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.
注意 boost::join 不会将两个向量复制到一个新容器中,而是生成一对覆盖两个容器跨度的迭代器(范围)。会有一些性能开销,但可能比首先将所有数据复制到新容器要少。
回答by aloisdg moving to codidact.com
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.
根据Kiril V. Lyadvinsky 的回答,我制作了一个新版本。此代码段使用模板和重载。有了它,你可以写vector3 = vector1 + vector2
和vector4 += vector3
。希望它能有所帮助。
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
}
回答by Ronald Souza
In the direction of Bradgonesurfing's answer, many times one doesn't really needto 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.
在 Bradgonesurfing 的回答的方向上,很多时候人们并不真的需要连接两个向量 (O(n)),而只是像连接 (O(1)) 一样处理它们。如果这是你的情况,它可以在不需要 Boost 库的情况下完成。
The trick is to create a vector proxy: a wrapper class which manipulates referencesto both vectors, externally seen as a single, contiguous one, which can then be accessed/traversed exactly like you would do on a real vector.
诀窍是创建一个向量代理:一个包装类,它处理对两个向量的引用,在外部被视为一个单一的、连续的,然后可以像在真实的向量上一样访问/遍历它。
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] << " "; // ----> Output: 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. In practice, it's a fast operation even when considering huge vectors, since you replace |B| (or |A|+|B|) element copies by zero. Also, it delivers exactly the desired behavior.
创建它是 O(1)(恒定时间),并且需要最少的额外内存分配。在实践中,即使考虑到巨大的向量,它也是一个快速的操作,因为你替换了 |B| (或 |A|+|B|)元素按零复制。此外,它提供了完全期望的行为。
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 notprovide 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 biggermay 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.
- It is not possible (or at least too far from easy) to globally sort a VecProxy, since not all elements pertain to the same container.
- 只有当你真正知道处理引用时你在做什么时,你才应该去做。此解决方案旨在针对所提出问题的特定目的,对此效果很好。如果您不确定引用的工作方式,在任何其他上下文中使用它可能会导致意外行为。
- 在这个例子中,AB并没有提供一种非const访问运算符([])。随意包含它,但请记住:由于 AB 包含引用,因此为其分配值也会影响 A 和/或 B 中的原始元素。无论这是否是一个理想的功能,这是一个特定于应用程序的问题,应该仔细考虑。
- 直接对 A 或 B 进行的任何更改(如赋值、排序等)也将“修改”AB。这不一定是坏事(实际上,它可能非常方便:AB 永远不需要显式更新以保持自身与 A 和 B 同步),但它肯定是一种必须注意的行为。重要的例外:将 A 和/或 B 调整为更大可能会导致它们在内存中重新分配(为了需要连续空间),这反过来会使 AB 无效。
- 因为每次访问一个元素之前都要进行一次测试(即“i < v1.size()”),VecProxy 访问时间虽然恒定,但也比向量慢一点。
- 这种方法可以推广到 n 个向量。我没试过,但应该没什么大不了的。
- 对 VecProxy 进行全局排序是不可能的(或者至少不是太容易),因为并非所有元素都属于同一个容器。
回答by D. Alex
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;
}
回答by Cogwheel
回答by user3360767
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());