简体   繁体   English

连接两个 std::vectors

[英]Concatenating two std::vectors

如何连接两个std::vector

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):如果您使用的是 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;
}

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.移动后,src 的元素处于未定义但可以安全销毁的状态,并且其之前的元素在最后直接转移到 dest 的新元素。

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.如果两个向量不包含完全相同类型的事物,则此模式很有用,因为您可以使用某些东西而不是std::back_inserter将一种类型转换为另一种类型。

With C++11, I'd prefer following to append vector b to a:使用 C++11,我更喜欢将向量 b 附加到 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.ab不重叠时,将不再使用b


This is std::move from <algorithm> , not the usual std::move from <utility> .这是来自<algorithm>的 std:: std::move ,而不是来自<utility>通常std::move

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:但是如果你使用 C++11,还有一种更通用的方法:

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

Also, not part of a question, but it is advisable to usereserve before appending for better performance.此外,这不是问题的一部分,但建议在附加之前使用reserve以获得更好的性能。 And if you are concatenating vector with itself, without reserving it fails, so you always should reserve .而且,如果您将 vector 与其自身连接,而不保留它会失败,因此您始终应该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:使用range v3 ,您可能会有一个惰性连接:

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,有一个来自C++17的算法std::merge ,在对输入向量进行排序时非常容易使用,

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

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

你应该使用vector::insert

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

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.如果您的目标只是为了只读目的而迭代值的范围,另一种方法是将两个向量包装在代理周围(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

Refer to https://stackoverflow.com/a/55838758/2379625 for more details, including the 'VecProxy' implementation as well as pros & cons.有关更多详细信息,包括“VecProxy”实现以及优缺点,请参阅https://stackoverflow.com/a/55838758/2379625

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

Here's a general purpose solution using C++11 move semantics:这是使用 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);
}

Note how this differs from append ing to a vector .请注意这与appendvector有何不同。

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

Using C++20 you can get rid of begin() and end() with ranges.使用 C++20,您可以使用范围摆脱 begin() 和 end()。

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

This solution might be a bit complicated, but boost-range has also some other nice things to offer.这个解决方案可能有点复杂,但是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;
}

Often ones intention is to combine vector a and b just iterate over it doing some operation.通常一个意图是结合向量ab只是迭代它做一些操作。 In this case, there is the ridiculous simple join function.在这种情况下,有可笑的简单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 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.出于某种原因,没有什么像boost::join(a,b,c)这样的,这可能是合理的。

For containers which offer push_back (string, vector, deque, ...):对于提供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):对于提供insert (地图、集合)的容器:

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::insert是您最好的选择,正如已多次回答的那样,例如:

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 .遗憾的是,没有办法构造const vector<int> ,如上所述,您必须先构造然后再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:如果您实际上正在寻找的是一个容器来保存这两个vector<int>的串联,那么您可能会得到更好的东西,如果:

  1. Your vector contains primitives您的vector包含基元
  2. Your contained primitives are of size 32-bit or smaller您包含的原语大小为 32 位或更小
  3. You want a const container你想要一个const容器

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 .如果以上都是真的,我建议使用char_type与你的vector中包含的基元的大小相匹配的basic_string You should include a static_assert in your code to validate these sizes stay consistent:您应该在代码中包含一个static_assert以验证这些大小是否保持一致:

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有关stringvector之间差异的更多信息,您可以在这里查看: https ://stackoverflow.com/a/35558008/2642059

For a live example of this code you can look here: http://ideone.com/7Iww3I有关此代码的实时示例,您可以在此处查看:http: //ideone.com/7Iww3I

You can do it with pre-implemented STL algorithms using a template for a polymorphic type use.您可以使用模板使用多态类型使用预先实现的 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;
}

You can clear the second vector if you don't want to use it further ( clear() method).如果您不想进一步使用它,可以清除第二个向量( clear()方法)。

Concatenate two std::vector-s with for loop in one std::vector .在一个std::vector中连接两个std::vector-sfor循环。

    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.方法1:分配新向量,其大小是两个原始向量的大小之和。

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.方法2:通过添加/插入向量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());

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. v1:1,2,3。

Description:描述:

While i int not v2 size, push back element , index i in v1 vector.当 i int 不是 v2 大小时,推回元素,索引 i 在 v1 向量中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM