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

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

Приведенные ответы на самом деле не объединяются. Они добавляют копию. Может быть использование (с точки зрения эффективности) для создания метода конкатенации std :: vector, однако это потребует некоторого сложного совместного использования управления узлами, и, вероятно, поэтому этого не было сделано.

FauChristian 15.02.2017 22:07

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

Cookie 16.05.2017 13:00

@lecaruyer Вы понимаете, что только что отметили вопрос, который задавали два года назад, как дубликат

eshirima 03.08.2017 15:47

Я единственный, кто задается вопросом, почему это не реализовано как a + b или a.concat(b) в стандартной библиотеке? Возможно, реализация по умолчанию будет неоптимальной, но каждое объединение массивов не требует микрооптимизации.

oseiskar 24.03.2018 11:40

годы эволюции, самая продвинутая перегрузка операторов из всех основных языков, система шаблонов, удваивающая сложность языка, и все же ответ - не v = v1 + v2;

Spike0xff 21.10.2019 19:08

Я предполагаю, что STL не хотел чрезмерно указывать язык на случай, если вы хотите, чтобы оператор делал что-то другое, например, добавляя векторы силы в физическую модель. В этом случае вы можете захотеть перегрузить forceVector1 + forceVector2, чтобы выполнить поэлементное добавление ясным и лаконичным кодом.

Jonathan Lidbeck 06.02.2020 23:51

@ Spike0xff, v = v1 + v2 имеет значение в математике, которое не объединяется. К нему также предъявляются некоторые требования, чтобы его можно было вычислить. Я бы предпочел метод добавления (сокращение того, что можно сделать с помощью insert) или перегрузку push back.

Stefano Buora 17.02.2021 17:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
763
7
428 597
25

Ответы 25

Я бы использовал функция вставки, что-то вроде:

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

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

Я бы только добавил код, чтобы сначала получить количество элементов, содержащихся в каждом векторе, и установить vector1 как самый большой. В противном случае вы делаете много ненужного копирования.

Joe Pineda 14.10.2008 20:11

У меня есть вопрос. Будет ли это работать, если vector1 и vector2 - это одни и те же векторы?

Alexander Rafferty 17.07.2011 13:36

Если у вас есть объединение нескольких векторов в один, полезно ли сначала вызвать reserve для вектора назначения?

Faheem Mitha 05.02.2012 03:07

@AlexanderRafferty: Только если vector1.capacity() >= 2 * vector1.size(). Что нетипично, если вы не позвонили в std::vector::reserve(). В противном случае вектор будет перераспределен, что сделает недействительными итераторы, переданные как параметры 2 и 3.

Drew Dormann 22.06.2012 00:30

@FaheemMitha: Поскольку аргументы insert являются векторами, он уже знает, сколько элементов впереди, и будет обрабатывать его сам. Если мы вставляли другие вещи, такие как массив, было бы полезно сначала зарезервировать место.

Aidin 14.04.2014 05:35

@ Эйдин, я понимаю. Благодарю за разъяснение.

Faheem Mitha 14.04.2014 12:57

@Khaur: Это настолько ужасно, что в это трудно поверить. Для реализации очень легко обнаружить итераторы с произвольным доступом, вычислить размер и предварительно зарезервировать необходимое пространство. Я думаю, что MSFT делает это даже для прямых итераторов.

Mooing Duck 05.04.2016 19:23

@MooingDuck Вы правы, я пропустил диспетчер и подумал, что версия итератора ввода применима ко всем типам итераторов. Версия с прямым итератором делает гораздо больше. Спасибо, что указали на это, я удалил свой первоначальный комментарий, чтобы он не появлялся без вашего.

Khaur 14.04.2016 19:14

Жаль, что в стандартной библиотеке нет более лаконичного выражения. .concat или += или что-то в этом роде

nmr 15.10.2016 02:32

@nmr В C++ это довольно лаконично.

YSC 08.11.2018 16:37

Трудно получить обзор всех различных ответов на этот вопрос. Подход std::vector::insert также был опубликован в нескольких других ответах, но у него больше всего голосов, поэтому я спрошу / заявлю здесь: использование insert должно иметь преимущество перед другими подходами, которые используют back_inserter, потому что insert потенциально может memcpy в одном объеме, в то время как подходы, использующие back_inserter, должны перебирать вектор, который нужно вставить, элемент за элементом. Я правильно понимаю?

j00hi 22.08.2019 18:34

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

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

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

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

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

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

Yogesh Arora 22.03.2010 16:16

@Yogesh: конечно, но ничто не мешает вам сначала вызвать в reserve. Причина, по которой std::copy иногда бывает полезна, заключается в том, что вы хотите использовать что-то другое, кроме back_inserter.

Roger Lipscombe 22.03.2010 21:36

Когда вы говорите «множественные выделения», это правда - но в худшем случае количество выделений - это журнал (количество добавленных записей), что означает, что стоимость добавления записи постоянна в количестве добавленных записей. (В принципе, не беспокойтесь об этом, если профилирование не покажет, что вам нужен резерв).

Martin Bonner supports Monica 20.11.2015 16:55

Вместо этого вы можете использовать std :: transform.

Martin Broadhurst 07.02.2016 19:01

копия - отстой, даже с запасом. vector :: insert позволит избежать всех проверок: quick-bench.com/bLJO4OfkAzMcWia7Pa80ynwmAIA

Denis Yaroshevskiy 29.07.2018 19:31

@DenisYaroshevskiy Разница в производительности разительная. Есть идеи, почему это происходит? Концептуально метод using_resize записывает пространство памяти res дважды, должно быть медленнее ??

Samuel Li 12.11.2020 07:47

@SamuelLi - в основном if > capacity_ в push_back, если проблема. Достаточно большой проблемы, что memset в resize не имеет значения.

Denis Yaroshevskiy 13.11.2020 10:14

Если вы используете C++ 11 и хотите переместить элементы, а не просто их копировать, вы можете использовать std::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 в конце.

Метод std :: make_move_iterator () помог мне при попытке объединить std :: vectors из std :: unique_ptr.

Knitschi 27.12.2014 16:43

В чем разница между этим и std::move(src.begin(), src.end(), back_inserter(dest))?

kshenoy 25.02.2020 10:30

@kshenoy, insert может выделить необходимый объем памяти за один ход. Когда back_inserter может привести к нескольким перераспределениям

yrHeTateJlb 01.10.2020 15:23

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

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(... тоже нельзя закинуть?

Class Skeleton 12.10.2015 18:33

insert уже справляется с этим. Кроме того, этот вызов erase эквивалентен resize.

Potatoswatter 27.12.2016 10:02

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

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

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


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

Неопределенное поведение, если a на самом деле равно b (что нормально, если вы знаете, что этого никогда не произойдет, но о нем стоит знать в коде общего назначения).

Martin Bonner supports Monica 20.11.2015 16:53

@MartinBonner Спасибо, что упомянули об этом. Возможно, мне следует вернуться к старому способу insert, который более безопасен.

Deqing 01.02.2016 06:31

просто добавьте следующую строку заголовка в начало: #include <iterator>

Manohar Reddy Poreddy 10.09.2016 15:07

Ах, ДРУГОЙ std :: move. Довольно сбивает с толку в первый раз.

xaxxon 16.09.2016 05:52

Это отличается от insert() с move_iterators? Если да, то как?

GPhilo 05.11.2018 13:52

Я добавил примечание о том, о каком std::move мы говорим, поскольку большинство людей не знают об этой перегрузке. Надеюсь, это улучшение.

YSC 08.11.2018 16:43

@Deqing Я не уверен, что вставка лучше ... Если a равно b, то, как только вы вставите несколько элементов, он перераспределит и аннулирует итераторы, переданные для вставки, которые затем будут продолжать использоваться, верно?

Jerry Jeremiah 22.09.2020 00:26

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

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]

Не знаю, почему это было отклонено. Возможно, это не самый эффективный способ сделать это, но он не неправильный и эффективный.

leeor_net 19.06.2016 22:11

И это работает, если вы передаете один и тот же вектор в качестве обоих параметров, чтобы объединить вектор с самим собой.

Jerry Jeremiah 22.09.2020 00:30

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

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

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

std:: выводится через поиск, зависящий от аргументов. end(a) будет достаточно.

Asu 13.10.2016 23:02

@Asu ADL добавит std:: только в том случае, если тип a исходит от std, что отменяет общий аспект.

Potatoswatter 27.12.2016 09:59

хорошая точка зрения. в данном случае это вектор, так что он все равно будет работать, но да, это лучшее решение.

Asu 27.12.2016 14:09

std :: begin () / end () были добавлены для коллекций (например, массивов), которые не имеют их в качестве функций-членов. Но у массивов также нет функции-члена insert (), и возникает вопрос: «Есть ли коллекция с insert (), но без begin () (которая работает с std :: begin ())?»

James Curran 04.10.2018 18:53

лучше не использовать резерв, так как это может повлечь за собой огромные накладные расходы. Смотрите здесь: stackoverflow.com/a/64102335/7110367

Ido Kessler 28.09.2020 16:43

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

Хотя этот фрагмент кода может решить проблему, он не объясняет, почему и как он отвечает на вопрос. Пожалуйста, включите объяснение вашего кода, так как это действительно помогает улучшить качество вашего сообщения. Отметившие / обозреватели:Для ответов только с кодом, таких как этот, голос "против", не удаляйте! (Примечание: этот ответ может быть достаточно простым, чтобы дать объяснение и, следовательно, отрицательные голоса не нужны. Вы все равно можете добавить объяснение, чтобы предотвратить появление дополнительных флагов NAA / VLQ.)

Scott Weldon 17.12.2016 03:38

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

Способ 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());

Что ваш ответ добавляет, чего еще не было в других ответах?

Mat 27.12.2016 09:53

@Mat: жирные символы.

marcv81 24.03.2017 16:34

Если после этого исходный вектор (-ы) больше не нужен, может быть лучше использовать std::move_iterator, чтобы элементы перемещались, а не копировались. (см. en.cppreference.com/w/cpp/iterator/move_iterator).

tmlen 23.02.2018 18:36

Что такое setcapacity? Что такое function: ?

L. F. 29.03.2019 15:08

@ L.F. Я думаю, он говорит о методе resize.

Matthieu H 13.12.2019 18:54

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

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

Демо.

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

wcochran 14.09.2020 01:21

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

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

Разве это не то же самое с ответом, данным Томом Риттером и Робертом Гэмблом в 2008 году?

IgNite 03.02.2020 05:06

Вот решение общего назначения, использующее семантику перемещения 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(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);
}

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

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

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

Так просто, но я никогда не думал об этом так!

Zimano 15.03.2019 22:41

Пример кода неверен. v1.insert(v2.end()... использует итератор в v2, чтобы указать позицию в v1.

David Stone 06.07.2019 01:16

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

qwr 09.12.2019 08:45

Вы можете вставить в начало, но это будет медленнее. Однако для истинной «конкатенации» порядок обычно имеет значение, так что это то, что вам нужно сделать.

David Stone 10.12.2019 05:12

Мне не нравится этот ответ, потому что вы не вставляете v2 после v1 во всех случаях (без указания этого примечания). В противном случае ваш ответ может быть более полным, если вы добавите решение, которое сохранит конкатенацию в другом векторе, а не изменит один из них.

King's jester 30.09.2020 23:24

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

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

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

Matthieu H 13.12.2019 18:46

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

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

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;

Я реализовал эту функцию, которая объединяет любое количество контейнеров, переходя от 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;
}

Есть алгоритм std::merge из C++ 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;
}

Я не думаю, что его легче использовать, чем std::vector::insert, но он работает с чем-то другим: объединением двух диапазонов в новый диапазон против вставки одного вектора в конец другого. Стоит упомянуть в ответе?

j b 05.12.2019 12:14

В порядке. Я понял, чего ждут в ответе. Я добавлю.

Pavan Chandaka 26.10.2020 22:03

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

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

Вы можете сделать это с помощью предварительно реализованных алгоритмов STL, используя шаблон для использования полиморфного типа.

#include <iostream>
#include <vector>
#include <algorithm>

template<typename T>

void concat(std::vector<T>& valuesa, std::vector<T>& valuesb){

     for_each(valuesb.begin(), valuesb.end(), [&](int value){ valuesa.push_back(value);});
}

int main()
{
    std::vector<int> values_p = {1,2,3,4,5};
    std::vector<int> values_s = {6,7};

   concat(values_p, values_s);

    for(auto& it : values_p){

        std::cout<<it<<std::endl;
    }

    return 0;
}

Вы можете очистить второй вектор, если не хотите его использовать в дальнейшем (метод clear()).

Соедините два std::vector-s с петлей for в один std::vector.

    std::vector <int> v1 {1, 2, 3}; //declare vector1
    std::vector <int> v2 {4, 5}; //declare vector2
    std::vector <int> suma; //declare vector suma

    for(int i = 0; i < v1.size(); i++) //for loop 1
    {
         suma.push_back(v1[i]);
    }

    for(int i = 0; i< v2.size(); i++) //for loop 2
    {
         suma.push_back(v2[i]);
    }

    for(int i = 0; i < suma.size(); i++) //for loop 3-output
    {
         std::cout << suma[i];
    }

помимо того, что он не работает, этот код в значительной степени неидиоматичен. По крайней мере, вы должны использовать итераторы auto вместо ручной индексации. Вам не важно, какой индекс вы объединяете, только то, что это выполняется последовательно.

Tarick Welling 08.06.2020 17:06

@TarickWelling Я не понимаю, почему вы сказали, что этот код не работает, не могли бы вы уточнить?

King's jester 30.09.2020 23:33

Вы проверяли дату моего комментария? Вы исправили ошибки в своем коде, теперь это просто не идиоматично.

Tarick Welling 01.10.2020 10:39

Попробуйте создать два вектора и добавить второй вектор к первому вектору, код:

std::vector<int> v1{1,2,3};
std::vector<int> v2{4,5};

for(int i = 0; i<v2.size();i++)
{
     v1.push_back(v2[i]);
}

v1: 1,2,3.

Описание:

Пока i int не имеет размера v2, отодвиньте элемент, индекс i в векторе v1.

Ваше описание нечеткое (и бесполезное, извините). В противном случае ваш ответ может быть более полным, если вы добавите второе решение, которое сохранит конкатенацию в другом векторе, а не изменит один из них.

King's jester 30.09.2020 23:37

Другие вопросы по теме