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

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

9X_concatenation

895
5

  • @FauChristian: Нет, с точки зрения эффективности это может быть бесполезно. Векторная память должна быть непрерывной, поэтому то, что вам предлагают, ...
22
Общее количество ответов: 22

Ответ #1

Ответ на вопрос: Объединение двух std :: vectors

vector1.insert( vector1.end(), vector2.begin(), vector2.end() ); 
9X_cpp
946
8

  • Если у вас есть объединение нескольких векторов в ...

Ответ #2

Ответ на вопрос: Объединение двух std :: vectors

Если вы используете C++ 11 и хотите переместить 9X_stdvector элементы, а не просто копировать их, вы 9X_cpp можете использовать std::move_iterator вместе со вставкой 9X_cpp (или копией):

#include #include #include int main(int argc, char** argv) { std::vector dest{1,2,3,4,5}; std::vector 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(std::cout, "\n") ); return 0; } 

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

#include #include #include int main(int argc, char** argv) { std::vector> dest{{1,2,3,4,5}, {3,4}}; std::vector> 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; } 

После 9X_concatenate перемещения элемент src остается в неопределенном, но 9X_vector безопасном для уничтожения состоянии, а 9X_concat его прежние элементы были перенесены непосредственно 9X_cpp в новый элемент dest в конце.

277
3

  • @kshenoy, `insert` может выделить ...

Ответ #3

Ответ на вопрос: Объединение двух std :: vectors

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

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

9X_concatenation

179
0

Ответ #4

Ответ на вопрос: Объединение двух std :: vectors

Или вы можете использовать:

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

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

89
4

  • метод копирования - не самый лучший способ. Он будет вызывать push_back несколько раз, ...

Ответ #5

Ответ на вопрос: Объединение двух std :: vectors

В C++ 11 я бы предпочел добавить вектор 9X_cxx b к a следующим образом:

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

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


Это std::move из 9X_stl-containers , а не обычный std::move из .

79
5

  • Неопределенное поведение, если a на самом деле равно b (что нормал ...

Ответ #6

Ответ на вопрос: Объединение двух std :: vectors

std::vector first; std::vector second; first.insert(first.end(), second.begin(), second.end()); 
9X_concat
44
0

Ответ #7

Ответ на вопрос: Объединение двух std :: vectors

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

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

Но 9X_vector если вы используете C++ 11, есть еще один 9X_concat общий способ:

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

Кроме того, это не является 9X_concatenation частью вопроса, но для повышения производительности 9X_vectors рекомендуется использовать reserve перед добавлением. И 9X_concatenation если вы объединяете вектор с самим собой, без 9X_concat его резервирования не удается, поэтому вам 9X_stdvector всегда следует reserve.


Итак, в основном то, что 9X_stdvector вам нужно:

template void Append(std::vector& a, const std::vector& b) { a.reserve(a.size() + b.size()); a.insert(a.end(), b.begin(), b.end()); } 

34
3

  • лучше не использовать резерв, так как это может повлечь за собой огромные накладные расходы. Посмотрите здесь: https://s ...

Ответ #8

Ответ на вопрос: Объединение двух std :: vectors

С range v3 у вас может быть ленивая конкатенация:

ranges::view::concat(v1, v2) 

Demo.

9X_concat

30
1

  • Я предполагаю, что это будет подходящий ответ примерно в 2023 году. ...

Ответ #9

Ответ на вопрос: Объединение двух std :: vectors

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

//vector v1,v2; if(v1.size()>v2.size()) { v1.insert(v1.end(),v2.begin(),v2.end()); } else { v2.insert(v2.end(),v1.begin(),v1.end()); } 

21
2

  • Вы также можете использовать быструю замену. @DavidStone Я отредактировал его, чтобы можно было изменить порядок ко ...

Ответ #10

Ответ на вопрос: Объединение двух std :: vectors

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

template std::vector& operator +=(std::vector& vector1, const std::vector& vector2) { vector1.insert(vector1.end(), vector2.begin(), vector2.end()); return vector1; } 

Тогда вы можете назвать это так:

vector1 += vector2; 

13
0

Ответ #11

Ответ на вопрос: Объединение двух std :: vectors

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

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

#include #include #include int main() { //DATA std::vector v1{2,4,6,8}; std::vector v2{12,14,16,18}; //MERGE std::vector dst; std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst)); //PRINT for(auto item:dst) std::cout<<" "; return 0; } 

11
1

  • Я не думаю, что его проще использовать, чем `std :: vector :: insert`, но он р ...

Ответ #12

Ответ на вопрос: Объединение двух std :: vectors

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

template inline void append_copy(std::vector& v1, const std::vector& 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 с сильной гарантией 9X_stl не может быть реализован в целом, если конструктор 9X_concat перемещения векторного элемента может бросать 9X_vector (что маловероятно, но все же).

9
0

Ответ #13

Ответ на вопрос: Объединение двух std :: vectors

Вам следует использовать vector::insert

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

9X_concat

9
1

  • Разве это не то же самое с ответом, данным ...

Ответ #14

Ответ на вопрос: Объединение двух std :: vectors

Если ваша цель - просто перебрать диапазон 9X_concatenation значений только для чтения, альтернативой 9X_stl-containers является обернуть оба вектора вокруг прокси 9X_stdvector (O (1)) вместо их копирования (O (n)), чтобы 9X_concatenate они сразу же воспринимаются как единый, непрерывный.

std::vector A{ 1, 2, 3, 4, 5}; std::vector B{ 10, 20, 30 }; VecProxy 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 

Обратитесь 9X_vectors к https://stackoverflow.com/a/55838758/2379625 для получения дополнительных сведений, включая 9X_concatenate реализацию VecProxy, а также плюсы и минусы.

8
0

Ответ #15

Ответ на вопрос: Объединение двух std :: vectors

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

template vector concat(vector &a, vector &b) { vector ret = vector(); copy(a.begin(), a.end(), back_inserter(ret)); copy(b.begin(), b.end(), back_inserter(ret)); return ret; } 

и 9X_concatenate используйте его так:

vector a = vector(); vector b = vector(); a.push_back(1); a.push_back(2); b.push_back(62); vector r = concat(a, b); 

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

6
0

Ответ #16

Ответ на вопрос: Объединение двух std :: vectors

Используя C++20, вы можете избавиться от 9X_stdvector begin() и end() с диапазонами.

#include std::ranges::copy(vec2, std::back_inserter(vec1)); 

или если вы 9X_concatenate хотите переместить элементы:

std::ranges::move(vec2, std::back_inserter(vec1)); 

5
0

Ответ #17

Ответ на вопрос: Объединение двух std :: vectors

Вот решение общего назначения, использующее 9X_vectors семантику перемещения C++ 11:

template std::vector concat(const std::vector& lhs, const std::vector& rhs) { if (lhs.empty()) return rhs; if (rhs.empty()) return lhs; std::vector 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 std::vector concat(std::vector&& lhs, const std::vector& rhs) { lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend()); return std::move(lhs); } template std::vector concat(const std::vector& lhs, std::vector&& rhs) { rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend()); return std::move(rhs); } template std::vector concat(std::vector&& lhs, std::vector&& 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); } 

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

4
0

Ответ #18

Ответ на вопрос: Объединение двух std :: vectors

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

template inline T operator+(const T & a, const T & b) { T res = a; res.insert(res.end(), b.begin(), b.end()); return res; } 

Следующее - просто используйте 9X_stdvector +:

vector a{1, 2, 3, 4}; vector b{5, 6, 7, 8}; for (auto x: a + b) cout << x << " "; cout << endl; 

Этот пример дает результат:


                
1 2 3 4 5 6 7 8

                

4
1

  • Использование`T operator + (const T & a, const T & b) `опасно, лучше использовать` vector <t> op ...

Ответ #19

Ответ на вопрос: Объединение двух std :: vectors

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

  • Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста [включите объяснение вашего кода] (// meta.stackexchange.com/q/114762/269535), так как это действительно помогает улучшить качеств ...

Ответ #20

Ответ на вопрос: Объединение двух std :: vectors

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

namespace internal { // Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if // appropriate template 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::value_type, typename std::decay_t
::value_type>, "Concatenate requires each container passed to it to have the same value_type"); if constexpr (std::is_lvalue_reference_v
) { 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)...); } } template 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 auto Concatenate(Head&& head, Tail&&... tail) { size_t totalSize = internal::TotalSize(head, tail...); std::vector
::value_type> result; result.reserve(totalSize); internal::AppendNoReserve(&result, std::forward
(head), std::forward(tail)...); return result; } 

3
0

Ответ #21

Ответ на вопрос: Объединение двух std :: vectors

Это решение может быть немного сложным, но 9X_vector boost-range может предложить и другие приятные вещи.

#include #include #include int main(int, char**) { std::vector a = { 1,2,3 }; std::vector b = { 4,5,6 }; boost::copy(b, std::back_inserter(a)); for (auto& iter : a) { std::cout << iter << " "; } return EXIT_SUCCESS; } 

Часто 9X_stl-containers намерение состоит в том, чтобы объединить 9X_concatenation vector a и b, просто перебирая его, выполняя 9X_vector некоторую операцию. В этом случае есть нелепая 9X_concatenation простая функция join.

#include #include #include #include int main(int, char**) { std::vector a = { 1,2,3 }; std::vector b = { 4,5,6 }; std::vector 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 d; boost::copy(boost::join(a, boost::join(b, c)), std::back_inserter(d)); for (auto& iter : d) { std::cout << iter << " "; } return EXIT_SUCCESS; } 

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

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

1
0

Ответ #22

Ответ на вопрос: Объединение двух std :: vectors

Для контейнеров, предлагающих push_back (строка, вектор, двухсторонняя 9X_stl-containers очередь, ...):

std::copy(std::begin(input), std::end(input), std::back_inserter(output))

и

для контейнеров, предлагающих 9X_concatenation insert (карты, наборы):

std::copy(std::begin(input), std::end(input), std::inserter(output, output.end()))

1
0