2008-10-14 3 views
445

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

+2

Ответы, приведенные, на самом деле не совпадают. Они добавляют копию. Может быть использование (для точки зрения эффективности) создания метода std :: vector concatenate, однако для этого потребуется некоторый сложный совместный подход к управлению узлами, и, вероятно, поэтому он не был выполнен. – FauChristian 2017-02-15 19:07:59

+1

@FauChristian: Нет, с точки зрения эффективности не может быть пользы. Векторная память должна быть непрерывной, поэтому предлагаемое вами невозможно. Если вам нужен «некоторый сложный совместный доступ к управлению узлами», и если бы вы таким образом изменили векторный класс, вы попали бы в deque. Даже тогда очень трудно повторно использовать память, как предполагалось, хотя она начнет быть немного более выполнимой. Я не думаю, что это в настоящее время реализовано. Главное, что при таком совместном использовании узлов управления (deque) конечный узел может быть частично пустым. – Cookie 2017-05-16 10:00:41

+1

@lecaruyer Вы понимаете, что вы просто отметили вопрос, который был задан два года назад, как дубликат. – eshirima 2017-08-03 12:47:50

ответ

107

Я бы использовать insert function, что-то вроде:

vector<int> a, b; 
//fill with data 
b.insert(b.end(), a.begin(), a.end()); 
503
vector1.insert(vector1.end(), vector2.begin(), vector2.end()); 
+41

Я бы только добавил код, чтобы сначала получить количество элементов, каждый из которых удерживается в векторе, и установить vector1 как тот, который будет наибольшим. Если вы это сделаете, вы делаете много ненужного копирования. – 2008-10-14 16:11:42

+23

У меня вопрос. Будет ли это работать, если vector1 и vector2 являются одинаковыми векторами? – 2011-07-17 09:36:28

+4

Если вы связываете несколько векторов с одним, полезно ли сначала вызвать «резерв» в векторе назначения? – 2012-02-04 23:07:59

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

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

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

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

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

105

Если вы используете C++ 11, и хотите, чтобы переместить элементы, а не просто копировать их, вы можете использовать зЬй :: move_iterator (http://en.cppreference.com/w/cpp/iterator/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; 
} 

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

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

4

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

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

26

С C++ 11, я предпочитаю следующее добавление вектора Ь к а:

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

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

2

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

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

г будет содержать [1,2,62]

0

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

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

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

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

С этим проведение правда, что вы можете просто сделать:

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

15

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

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

Но если вы используете C++ 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()); 
} 
2
vector<int> v1 = {1, 2, 3, 4, 5}; 
vector<int> v2 = {11, 12, 13, 14, 15}; 
copy(v2.begin(), v2.end(), back_inserter(v1)); 
0

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

Способ 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: Дозапись вектор А путем добавления/вставки элементов вектора 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

Вот общее решение цели с помощью 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(result.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.

Смежные вопросы