Приведенные ответы на самом деле не объединяются. Они добавляют копию. Может быть использование (с точки зрения эффективности) для создания метода конкатенации std :: vector, однако это потребует некоторого сложного совместного использования управления узлами, и, вероятно, поэтому это не было сделано.
FauChristian
8
@FauChristian: Нет, с точки зрения эффективности не может быть пользы. Векторная память должна быть непрерывной, поэтому то, что вы предлагаете, невозможно. Если вы хотите «некоторого сложного совместного использования управления узлами», и если вы хотите изменить векторный класс таким образом, вы получите деку. Даже тогда очень сложно повторно использовать память предложенным способом, хотя она стала бы немного более выполнимой. Я не думаю, что это в настоящее время реализовано. Главное, что при таком совместном использовании узлов управления (deque) конечный узел может быть частично пустым.
Cookie
4
@lecaruyer Вы понимаете, что только что отметили вопрос, который был задан за два года до того, как дубликат
eshirima
9
Я один задаюсь вопросом, почему это не реализовано как a + bили a.concat(b)в стандартной библиотеке? Может быть, реализация по умолчанию будет неоптимальной, но объединение каждого массива не нуждается в
микрооптимизации
10
годы эволюции, самая совершенная перегрузка операторов из любого основного языка, система шаблонов, которая удваивает сложность языка, и все же ответ не v = v1 + v2;
Я бы добавил код только для того, чтобы сначала получить количество элементов, содержащихся в каждом векторе, и установить вектор1 как самый большой. Если вы делаете иначе, вы делаете много ненужного копирования.
Джо Пинеда
34
У меня вопрос. Будет ли это работать, если vector1 и vector2 одинаковые векторы?
Александр Рафферти
6
Если вы объединяете несколько векторов в один, полезно ли reserveсначала вызывать вектор назначения?
Фахим Митха
33
@AlexanderRafferty: Только если vector1.capacity() >= 2 * vector1.size(). Что нетипично, если вы не позвонили std::vector::reserve(). В противном случае вектор будет перераспределен, делая недействительными итераторы, переданные в качестве параметров 2 и 3.
Дрю Дорманн
28
Жаль, что в стандартной библиотеке нет более краткого выражения. .concatили +=или что - то
мр
194
Если вы используете C ++ 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"));return0;}
Это не будет более эффективным для примера с целыми числами, поскольку их перемещение не более эффективно, чем их копирование, но для структуры данных с оптимизированными перемещениями можно избежать копирования ненужного состояния:
#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()));return0;}
После перемещения элемент src остается в неопределенном, но безопасном для уничтожения состоянии, а его прежние элементы были переданы непосредственно новому элементу dest в конце.
Этот шаблон полезен, если два вектора не содержат абсолютно одинаковую вещь, потому что вы можете использовать что-то вместо std :: back_inserter для преобразования из одного типа в другой.
метод копирования не очень хороший способ. Он будет вызывать push_back несколько раз, что означает, что если нужно вставить много элементов, это может означать многократное перераспределение. лучше использовать вставку, поскольку реализация вектора могла бы сделать некоторую оптимизацию, чтобы избежать перераспределений. он может зарезервировать память перед началом копирования
Йогеш Арора
7
@Yogesh: само собой разумеющееся, но ничто не мешает вам позвонить reserveпервым. Причина std::copyиногда полезна, если вы хотите использовать что-то другое back_inserter.
Роджер Липскомб
Когда вы говорите «множественные распределения», это правда - но количество распределений в худшем случае (количество добавленных записей) - это означает, что стоимость добавления записи постоянна в количестве добавленных записей. (По сути, не беспокойтесь об этом, если профилирование не показывает, что вам нужен резерв).
Мартин Боннер поддерживает Монику
Возможно, вы захотите использовать std :: transform для этого.
Неопределенное поведение, если a на самом деле - b (что нормально, если вы знаете, что этого никогда не произойдет, но стоит знать об этом в коде общего назначения).
Мартин Боннер поддерживает Монику
1
@MartinBonner Спасибо за упоминание этого. Возможно, мне следует вернуться к старому insert, более безопасному способу.
Deqing
15
Ах, ДРУГОЙ std :: move. Весьма сбивает с толку первый раз, когда вы видите это.
xaxxon
1
Это отличается от insert()с move_iteratorс? Если так, то как?
GPhilo
1
Я добавил примечание о том, что std::moveмы здесь говорим, так как большинство людей не знают этой перегрузки. Надеюсь, это улучшение.
Кроме того, не является частью вопроса, но желательно использовать reserveперед добавлением для повышения производительности. И если вы соединяете вектор с самим собой, без резервирования он не удастся, так что вам всегда следует reserve.
@Asu ADL будет добавляться только в том std::случае, если от него aпоступает тип std, который игнорирует общий аспект.
Potatoswatter
хорошая точка зрения. в данном случае это вектор, так что он будет работать в любом случае, но да, это лучшее решение.
Асу
std :: begin () / end () были добавлены для коллекций (таких как массивы), которые не имеют их в качестве функций-членов. Но массивы также не имеют функции-члена insert () и вызывают вопрос «Существует ли коллекция с insert (), но без begin () (которая работает с std :: begin ())?»
Так просто, но я никогда не думал об этом таким образом!
Зимано
2
Пример кода неверен. v1.insert(v2.end()...использует итератор в, v2чтобы указать позицию в v1.
Дэвид Стоун
Вы также можете использовать быстрый обмен. @DavidStone Я отредактировал его, чтобы можно было изменить порядок конкатов. Можно ли добавить в начало вектора?
QWR
Вы можете вставить в начало, но это будет медленнее. Однако для истинного «объединения» порядок обычно имеет значение, и это то, что вам нужно сделать.
Дэвид Стоун
7
Если вы хотите иметь возможность краткого объединения векторов, вы можете перегрузить +=оператор.
Подобное append_moveсо строгой гарантией не может быть реализовано вообще, если конструктор перемещения векторного элемента может бросить (что маловероятно, но все же).
Я не думаю, что это легче использовать, чем std::vector::insert, но это делает что-то другое: объединение двух диапазонов в новый диапазон против вставки одного вектора в конце другого. Стоит упомянуть в ответе?
ДБ
4
Если ваша цель состоит в том, чтобы просто перебрать диапазон значений для целей только для чтения, альтернативой является обтекание обоих векторов вокруг прокси (O (1)) вместо их копирования (O (n)), чтобы их можно было быстро увидеть как единый, непрерывный.
Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода , так как это действительно помогает улучшить качество вашего сообщения. Флаггеры / рецензенты: для ответов только с кодом, таких как этот, downvote, не удаляйте! (Примечание: этот ответ на самом деле может быть достаточно простым, чтобы дать объяснение, и, следовательно, понизить голосование, излишне. Вы все еще можете добавить объяснение, чтобы предотвратить больше флагов NAA / VLQ.)
Скотт Уэлдон
2
Я реализовал эту функцию, которая объединяет любое количество контейнеров, переходя от rvalue-ссылок и копируя иначе
namespaceinternal{// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if// appropriatetemplate<typenameTarget,typenameHead,typename...Tail>voidAppendNoReserve(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");ifconstexpr(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));}ifconstexpr(sizeof...(Tail)>0){AppendNoReserve(target, std::forward<Tail>(tail)...);}}template<typenameHead,typename...Tail>size_tTotalSize(constHead& head,constTail&... tail){ifconstexpr(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<typenameHead,typename...Tail>autoConcatenate(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;}
Если то, что вы ищете, - это способ добавить вектор к другому после создания, то 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>, вам может быть доступно что-то лучше, если:
Ваш vector содержит примитивы
Ваши содержащиеся примитивы имеют размер 32 бита или меньше
Вы хотите constконтейнер
Если все вышеприведенное верно, я бы предложил использовать тот, basic_stringкто char_typeсоответствует размеру примитива, содержащегося в вашем vector. Вы должны включить static_assertв свой код, чтобы подтвердить соответствие этих размеров:
Это решение может быть немного сложным, но 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 iteratorfor(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), что может быть разумным.
Вы forне правы. Допустимые индексы в векторе от 0 до size()-1. Вы должны выполнить условия завершения i < v1.size(), используя <not <=. Использование неправильного условия обращается к памяти за пределами контейнера.
Доменная печь
кроме того, что он не работает, этот код сильно не идиоматичен. Вы должны по крайней мере использовать autoитераторы вместо ручной индексации. Вам не важно, какой индекс вы объединяете, только то, что он выполняется последовательно.
Тарик Веллинг
Можете ли вы объяснить, почему вы используете size()-1два условия цикла? Это пропускает последние векторные элементы. Третий цикл является единственным правильным сейчас.
Доменная печь
-3
Если честно, вы можете быстро объединить два вектора, скопировав элементы из двух векторов в другой или просто добавив только один из двух векторов !. Это зависит от вашей цели.
Способ 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());
Что добавляет ваш ответ, который еще не был представлен в других ответах?
Мат
13
@Mat: жирные буквы.
marcv81
Если исходный вектор (ы) больше не нужен после, возможно, лучше использовать его, std::move_iteratorчтобы элементы перемещались, а не копировались. (см. en.cppreference.com/w/cpp/iterator/move_iterator ).
a + b
илиa.concat(b)
в стандартной библиотеке? Может быть, реализация по умолчанию будет неоптимальной, но объединение каждого массива не нуждается вОтветы:
источник
reserve
сначала вызывать вектор назначения?vector1.capacity() >= 2 * vector1.size()
. Что нетипично, если вы не позвонилиstd::vector::reserve()
. В противном случае вектор будет перераспределен, делая недействительными итераторы, переданные в качестве параметров 2 и 3..concat
или+=
или что - тоЕсли вы используете C ++ 11 и хотите перемещать элементы, а не просто копировать их, вы можете использовать
std::move_iterator
вместе со insert (или copy):Это не будет более эффективным для примера с целыми числами, поскольку их перемещение не более эффективно, чем их копирование, но для структуры данных с оптимизированными перемещениями можно избежать копирования ненужного состояния:
После перемещения элемент src остается в неопределенном, но безопасном для уничтожения состоянии, а его прежние элементы были переданы непосредственно новому элементу dest в конце.
источник
std::move(src.begin(), src.end(), back_inserter(dest))
?Я бы использовал функцию вставки , что-то вроде:
источник
Или вы можете использовать:
Этот шаблон полезен, если два вектора не содержат абсолютно одинаковую вещь, потому что вы можете использовать что-то вместо std :: back_inserter для преобразования из одного типа в другой.
источник
reserve
первым. Причинаstd::copy
иногда полезна, если вы хотите использовать что-то другоеback_inserter
.В C ++ 11 я бы предпочел добавить вектор b к a:
когда
a
иb
не перекрываются, иb
больше не будут использоваться.Это
std::move
из<algorithm>
, а не обычныйstd::move
с<utility>
.источник
insert
, более безопасному способу.insert()
сmove_iterator
с? Если так, то как?std::move
мы здесь говорим, так как большинство людей не знают этой перегрузки. Надеюсь, это улучшение.источник
Я предпочитаю тот, который уже упоминался:
Но если вы используете C ++ 11, есть еще один общий способ:
Кроме того, не является частью вопроса, но желательно использовать
reserve
перед добавлением для повышения производительности. И если вы соединяете вектор с самим собой, без резервирования он не удастся, так что вам всегда следуетreserve
.Итак, в основном то, что вам нужно:
источник
std::
выводится через аргумент-зависимый поиск .end(a)
будет достаточно.std::
случае, если от негоa
поступает типstd
, который игнорирует общий аспект.С диапазоном v3 у вас может быть ленивая конкатенация:
Demo .
источник
Вы должны использовать vector :: insert
источник
Общий прирост производительности для СЦЕПИТЬ, чтобы проверить размер векторов. И объединить / вставить меньший с большим.
источник
v1.insert(v2.end()...
использует итератор в,v2
чтобы указать позицию вv1
.Если вы хотите иметь возможность краткого объединения векторов, вы можете перегрузить
+=
оператор.Тогда вы можете назвать это так:
источник
Если вы заинтересованы в строгой гарантии исключения (когда конструктор копирования может выдать исключение):
Подобное
append_move
со строгой гарантией не может быть реализовано вообще, если конструктор перемещения векторного элемента может бросить (что маловероятно, но все же).источник
v1.erase(...
бросить тоже?insert
уже справляется с этим. Кроме того, этот вызовerase
эквивалентенresize
.Добавьте это в свой заголовочный файл:
и используйте это так:
r будет содержать [1,2,62]
источник
Вот решение общего назначения с использованием семантики перемещения C ++ 11:
Обратите внимание, как это отличается от
append
вvector
.источник
Вы можете подготовить свой собственный шаблон для оператора +:
Следующая вещь - просто используйте +:
Этот пример дает вывод:
источник
T operator+(const T & a, const T & b)
опасно, лучше использоватьvector<T> operator+(const vector<T> & a, const vector<T> & b)
.Есть алгоритм
std::merge
из C ++ 17 , который очень прост в использовании,Ниже приведен пример:
источник
std::vector::insert
, но это делает что-то другое: объединение двух диапазонов в новый диапазон против вставки одного вектора в конце другого. Стоит упомянуть в ответе?Если ваша цель состоит в том, чтобы просто перебрать диапазон значений для целей только для чтения, альтернативой является обтекание обоих векторов вокруг прокси (O (1)) вместо их копирования (O (n)), чтобы их можно было быстро увидеть как единый, непрерывный.
Обратитесь к https://stackoverflow.com/a/55838758/2379625 для получения более подробной информации, включая реализацию VecProxy, а также плюсы и минусы.
источник
источник
Я реализовал эту функцию, которая объединяет любое количество контейнеров, переходя от rvalue-ссылок и копируя иначе
источник
Если то, что вы ищете, - это способ добавить вектор к другому после создания, то
vector::insert
это ваша лучшая ставка, на которую уже отвечали несколько раз, например:К сожалению, нет способа построить
const vector<int>
, как выше, вы должны построить, а затемinsert
.Если то, что вы на самом деле ищете, является контейнером для объединения этих двух элементов
vector<int>
, вам может быть доступно что-то лучше, если:vector
содержит примитивыconst
контейнерЕсли все вышеприведенное верно, я бы предложил использовать тот,
basic_string
ктоchar_type
соответствует размеру примитива, содержащегося в вашемvector
. Вы должны включитьstatic_assert
в свой код, чтобы подтвердить соответствие этих размеров:С этим подтверждением вы можете просто сделать:
Для получения дополнительной информации о различиях между
string
иvector
вы можете посмотреть здесь: https://stackoverflow.com/a/35558008/2642059Живой пример этого кода вы можете посмотреть здесь: http://ideone.com/7Iww3I
источник
Это решение может быть немного сложным, но
boost-range
есть и другие приятные предложения.Часто намерение состоит в том, чтобы объединить вектор
a
иb
просто перебрать его, выполнив некоторую операцию. В этом случае есть смешная простаяjoin
функция.Для больших векторов это может быть преимуществом, так как нет копирования. Его также можно использовать для простого копирования обобщений в несколько контейнеров.
По какой-то причине нет ничего подобного
boost::join(a,b,c)
, что может быть разумным.источник
Вы можете сделать это с помощью предварительно реализованных алгоритмов STL, используя шаблон для использования полиморфного типа.
Вы можете очистить второй вектор, если не хотите использовать его дальше (
clear()
метод).источник
Соединить два
std::vector-s
сfor
петлей в одномstd::vector
.Пример:
Напишите этот код в
main()
.источник
for
не правы. Допустимые индексы в векторе от 0 доsize()-1
. Вы должны выполнить условия завершенияi < v1.size()
, используя<
not<=
. Использование неправильного условия обращается к памяти за пределами контейнера.auto
итераторы вместо ручной индексации. Вам не важно, какой индекс вы объединяете, только то, что он выполняется последовательно.size()-1
два условия цикла? Это пропускает последние векторные элементы. Третий цикл является единственным правильным сейчас.Если честно, вы можете быстро объединить два вектора, скопировав элементы из двух векторов в другой или просто добавив только один из двух векторов !. Это зависит от вашей цели.
Способ 1: назначить новый вектор с его размером является суммой размеров двух исходных векторов.
Способ 2: добавить вектор A, добавив / вставив элементы вектора B.
источник
std::move_iterator
чтобы элементы перемещались, а не копировались. (см. en.cppreference.com/w/cpp/iterator/move_iterator ).setcapacity
? Что такоеfunction:
?resize
методе.