Как объединить два std::vector
s?
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
Если вы используете С++ 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 в конце.
Я бы использовал функцию insert, например:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
Или вы могли бы использовать:
std::copy(source.begin(), source.end(), std::back_inserter(destination));
Этот шаблон полезен, если два вектора не содержат точно такого же типа вещей, потому что вы можете использовать что-то вместо std:: back_inserter для преобразования из одного типа в другой.
reserve
. Причина, по которой std::copy
иногда полезна, заключается в том, что вы хотите использовать что-то, кроме back_inserter
.
С С++ 11 я бы предпочел добавить вектор b к a:
std::move(b.begin(), b.end(), std::back_inserter(a));
когда a
и b
не перекрываются, и b
больше не будет использоваться.
Это std::move
из <algorithm>
, а не обычный std::move
из <utility>
.
insert
, который является более безопасным.
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
Я предпочитаю тот, который уже упоминался:
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());
}
std::
выводится через аргумент-зависимый поиск . end(a)
будет достаточно.
std::
если тип a
происходит от std
, что исключает общий аспект.
Вы должны использовать вектор :: insert
v1.insert(v1.end(), v2.begin(), v2.end());
Если вы заинтересованы в надежной гарантии исключения (когда конструктор копирования может вызвать исключение):
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
с сильной гарантией не может быть реализован вообще, если конструктор перемещения элемента вектора может выбросить (что маловероятно, но все же).
v1.erase(...
тоже скинуть?
insert
уже обрабатывает это. Кроме того, этот вызов erase
эквивалентен resize
.
Здесь универсальное решение, использующее С++ 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
.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
Общее повышение производительности для конкатенации - проверка размера векторов. И объедините/вставьте меньший с большим.
//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());
}
Добавьте этот файл в свой файл заголовка:
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]
Вы можете подготовить свой собственный шаблон для оператора +:
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
Это решение может быть немного сложным, но у 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)
, что может быть разумным.
Честно говоря, вы могли бы быстро объединить два вектора путем копирования элементов из двух векторов в другой или просто добавить один из двух векторов!. Это зависит от вашей цели.
Метод 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());
Если то, что вы ищете, это способ добавить вектор к другому после создания, 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
содержит примитивы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/questions/4557009/vector-vs-string
Для живого примера этого кода вы можете посмотреть здесь: http://ideone.com/7Iww3I