Конкатенация двух стандартных: векторов - PullRequest
579 голосов
/ 14 октября 2008

Как объединить два std::vector с?

Ответы [ 18 ]

4 голосов
/ 06 мая 2014

Если вас интересует надежная гарантия исключения (когда конструктор копирования может выдать исключение):

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 с надежной гарантией вообще не может быть реализовано, если конструктор перемещения векторного элемента может бросить (что маловероятно, но все же).

3 голосов
/ 08 марта 2018

Вот решение общего назначения с использованием семантики перемещения 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);
}

Обратите внимание, как это отличается от append до vector.

3 голосов
/ 16 декабря 2016
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
3 голосов
/ 11 ноября 2015

Добавьте это в свой заголовочный файл:

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]

1 голос
/ 31 июля 2018

Вы можете подготовить свой собственный шаблон для оператора +:

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;

Этот пример дает вывод:

<blockquote>1 2 3 4 5 6 7 8</blockquote>
0 голосов
/ 06 декабря 2018

Это решение может быть немного сложным, но у 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;
}

Часто намерение состоит в том, чтобы объединить вектор a и b, просто повторив его, выполнив некоторую операцию. В этом случае есть смешная простая функция 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;
}

Для больших векторов это может быть преимуществом, так как нет копирования. Его также можно использовать для простого копирования обобщений в несколько контейнеров.

По какой-то причине нет ничего похожего на boost::join(a,b,c), что может быть разумным.

0 голосов
/ 27 декабря 2016

Если честно, вы можете быстро объединить два вектора, скопировав элементы из двух векторов в другой или просто добавив один из двух векторов! Это зависит от вашей цели.

Метод 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

Метод 2: Добавить вектор A, добавив / вставив элементы вектора 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());
0 голосов
/ 22 февраля 2016

Если то, что вы ищете, это способ добавить вектор к другому после создания, 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> s, вам может быть доступно что-то лучшее, если:

  1. Ваш vector содержит примитивы
  2. Ваши примитивы имеют размер 32 бита или меньше
  3. Вы хотите const контейнер

Если все вышеприведенное верно, я бы предложил использовать basic_string, чей char_type соответствует размеру примитива, содержащегося в вашем vector. Вы должны включить static_assert в свой код, чтобы подтвердить соответствие этих размеров:

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

С этим значением true вы можете просто:

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

Дополнительную информацию о различиях между string и vector вы можете посмотреть здесь: https://stackoverflow.com/a/35558008/2642059

Живой пример этого кода вы можете посмотреть здесь: http://ideone.com/7Iww3I

...