Объединение двух std::vectors

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

Ответ 1

vector1.insert( vector1.end(), vector2.begin(), vector2.end() );

Ответ 2

Если вы используете С++ 11 и хотите перемещать элементы, а не просто копировать их, вы можете использовать std::move_iterator вместе со insert (или copy):

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

Это не будет более эффективным для примера с целочисленными значениями, поскольку перемещение их не более эффективно, чем их копирование, но для структуры данных с оптимизированными перемещениями можно избежать копирования ненужного состояния:

#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 в конце.

Ответ 3

Я бы использовал функцию insert, например:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());

Ответ 4

Или вы могли бы использовать:

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

Этот шаблон полезен, если два вектора не содержат точно такого же типа вещей, потому что вы можете использовать что-то вместо std:: back_inserter для преобразования из одного типа в другой.

Ответ 5

В С++ 11 я бы предпочел добавить вектор b к a:

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

когда a и b не перекрываются, и b больше не будет использоваться.


Это std::move из <algorithm>, а не обычный std::move из <utility>.

Ответ 6

std::vector<int> first;
std::vector<int> second;

first.insert(first.end(), second.begin(), second.end());

Ответ 7

Я предпочитаю тот, который уже упоминался:

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

Но если вы используете С++ 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());
}

Ответ 8

Вы должны использовать вектор :: insert

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

Ответ 10

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

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

Ответ 11

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

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]

Ответ 12

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

Ответ 13

Здесь универсальное решение, использующее С++ 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.

Ответ 14

Общее повышение производительности для конкатенации - проверка размера векторов. И объедините/вставьте меньший с большим.

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

Ответ 15

Если вы хотите иметь возможность краткого объединения векторов, вы можете перегрузить оператор +=.

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;

Ответ 16

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

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

Ответ 17

Если то, что вы ищете, это способ добавить вектор к другому после создания, vector::insert - ваш лучший выбор, как было несколько раз ответ, например:

vector<int> first = {13};
const vector<int> second = {42};

first.insert(first.end(), second.cbegin(), second.cend());

К сожалению, нет способа построить a const vector<int>, как и выше, вы должны построить, а затем insert.


Если то, что вы действительно ищете, является контейнером для хранения конкатенации этих двух vector<int> s, может быть что-то более доступное для вас, если:

  • Ваш vector содержит примитивы
  • Скрытые примитивы размером 32 бит или меньше
  • Вам нужен контейнер 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 вы можете посмотреть здесь: fooobar.com/questions/16654/...

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

Ответ 18

Это решение может быть немного сложным, но у 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), что может быть разумным.

Ответ 19

Я реализовал эту функцию, которая объединяет любое количество контейнеров, переходя от rvalue-ссылок и копируя иначе

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

Ответ 20

Существует алгоритм std::merge из С++ 17, который очень прост в использовании,

Ниже приведен пример:

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

Ответ 21

Если ваша цель состоит в том, чтобы просто выполнить итерацию по всему диапазону значений только для чтения, альтернативой является обтекание обоих векторов вокруг прокси (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

std::cout << AB[6]; // ----> 20

Обратитесь к fooobar.com/questions/46176/... за более подробной информацией, включая реализацию VecProxy, а также профи и разработчики. минусы.

Ответ 22

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

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