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

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


person Community    schedule 14.10.2008    source источник
comment
Приведенные ответы на самом деле не объединяются. Они добавляют копию. Может быть использование (с точки зрения эффективности) для создания метода конкатенации std :: vector, однако это потребует некоторого сложного совместного использования управления узлами, и, вероятно, поэтому этого не было сделано.   -  person Douglas Daseeco    schedule 15.02.2017
comment
@FauChristian: Нет, с точки зрения эффективности это может быть бесполезно. Векторная память должна быть непрерывной, поэтому то, что вам предлагают, невозможно. Если вам нужно какое-то сложное совместное использование управления узлами, и если вы измените класс векторов таким образом, вы получите двухстороннюю очередь. Даже в этом случае очень сложно повторно использовать память предложенным способом, хотя это станет немного более осуществимым. Я не думаю, что сейчас это реализовано. Главное, что при таком совместном использовании узлов управления (двухсторонней очереди) конечный узел может быть частично пустым.   -  person Cookie    schedule 16.05.2017
comment
Я единственный, кто задается вопросом, почему это не реализовано как a + b или a.concat(b) в стандартной библиотеке? Возможно, реализация по умолчанию будет неоптимальной, но каждое объединение массивов не требует микрооптимизации.   -  person oseiskar    schedule 24.03.2018
comment
годы эволюции, самая продвинутая перегрузка операторов из всех основных языков, система шаблонов, удваивающая сложность языка, и все же ответ - не v = v1 + v2;   -  person Spike0xff    schedule 21.10.2019
comment
Я предполагаю, что STL не хотел чрезмерно указывать язык на случай, если вы хотите, чтобы оператор делал что-то другое, например, добавляя векторы силы в физическую модель. В этом случае вы можете захотеть перегрузить forceVector1 + forceVector2, чтобы выполнить поэлементное добавление в ясном и кратком коде.   -  person Jonathan Lidbeck    schedule 06.02.2020
comment
@ Spike0xff, v = v1 + v2 имеет значение в математике, которое не объединяется. К нему также предъявляются некоторые требования, чтобы его можно было вычислить. Я бы предпочел метод добавления (ярлык того, что можно сделать с помощью insert) или перегрузку push back.   -  person Stefano Buora    schedule 17.02.2021


Ответы (25)


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

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

person Alex    schedule 23.02.2014
comment
Метод std :: make_move_iterator () помог мне при попытке объединить std :: vectors из std :: unique_ptr. - person Knitschi; 27.12.2014
comment
В чем разница между этим и std::move(src.begin(), src.end(), back_inserter(dest))? - person kshenoy; 25.02.2020
comment
@kshenoy, insert может выделить необходимый объем памяти за один ход. Когда back_inserter может привести к нескольким перераспределениям - person yrHeTateJlb; 01.10.2020

Я бы использовал функцию вставки, например:

vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
person Tom Ritter    schedule 14.10.2008

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

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

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

person Roger Lipscombe    schedule 14.10.2008
comment
метод копирования - не самый лучший способ. Он будет вызывать push_back несколько раз, что означает, что если нужно вставить много элементов, это может означать несколько перераспределений. лучше использовать вставку, так как реализация вектора может сделать некоторую оптимизацию, чтобы избежать перераспределения. он может зарезервировать память перед началом копирования - person Yogesh Arora; 22.03.2010
comment
@Yogesh: конечно, но ничто не мешает тебе сначала позвонить reserve. Причина, по которой std::copy иногда бывает полезна, заключается в том, что вы хотите использовать что-то другое, кроме back_inserter. - person Roger Lipscombe; 22.03.2010
comment
Когда вы говорите о множественных выделениях, это правда, но количество выделений в худшем случае - это журнал (количество добавленных записей), что означает, что стоимость добавления записи постоянна в количестве добавленных записей. (В принципе, не беспокойтесь об этом, если профилирование не покажет, что вам нужен резерв). - person Martin Bonner supports Monica; 20.11.2015
comment
Вместо этого вы можете использовать std :: transform. - person Martin Broadhurst; 07.02.2016
comment
копия - отстой, даже с запасом. vector :: insert позволит избежать всех проверок: quick-bench.com/bLJO4OfkAzMcWia7Pa80ynwmAIA - person Denis Yaroshevskiy; 29.07.2018
comment
@DenisYaroshevskiy Разница в производительности разительная. Есть идеи, почему это происходит? По идее, метод using_resize дважды записывает пространство памяти res, должно быть медленнее ?? - person Samuel Li; 12.11.2020
comment
@SamuelLi - в основном if > capacity_ в push_back, если проблема. Достаточно большой проблемы, что memset в resize не имеет значения. - person Denis Yaroshevskiy; 13.11.2020

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

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

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


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

person Deqing    schedule 12.06.2015
comment
Неопределенное поведение, если a на самом деле равно b (что нормально, если вы знаете, что этого никогда не произойдет, но о нем стоит знать в коде общего назначения). - person Martin Bonner supports Monica; 20.11.2015
comment
@MartinBonner Спасибо, что упомянули об этом. Возможно, мне следует вернуться к старому insert способу, который более безопасен. - person Deqing; 01.02.2016
comment
просто добавьте следующую строку заголовка в начало: #include ‹iterator› - person Manohar Reddy Poreddy; 10.09.2016
comment
Ах, ДРУГОЙ std :: move. Довольно сбивает с толку, когда видишь это в первый раз. - person xaxxon; 16.09.2016
comment
Это отличается от insert() с move_iterators? Если да, то как? - person GPhilo; 05.11.2018
comment
Я добавил примечание о том, о чем std::move мы здесь говорим, поскольку большинство людей не знают об этой перегрузке. Надеюсь, это улучшение. - person YSC; 08.11.2018
comment
@Deqing Я не уверен, что вставка лучше ... Если a равно b, то, как только вы вставите несколько элементов, он перераспределит и аннулирует итераторы, переданные для вставки, которые затем будут продолжать использоваться, верно? - person Jerry Jeremiah; 22.09.2020

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

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());
}
person ST3    schedule 10.06.2016
comment
std:: выводится с помощью поиска, зависящего от аргументов. end(a) будет достаточно. - person Asu; 13.10.2016
comment
@Asu ADL добавит std:: только в том случае, если тип a исходит из std, что нарушает общий аспект. - person Potatoswatter; 27.12.2016
comment
хорошая точка зрения. в данном случае это вектор, так что он все равно будет работать, но да, это лучшее решение. - person Asu; 27.12.2016
comment
std :: begin () / end () были добавлены для коллекций (например, массивов), которые не имеют их в качестве функций-членов. Но у массивов также нет функции-члена insert (), и возникает вопрос: есть ли коллекция с insert (), но без begin () (которая работает с std :: begin ())? - person James Curran; 04.10.2018
comment
лучше не использовать резерв, так как это может повлечь за собой огромные накладные расходы. Посмотрите здесь: stackoverflow.com/a/64102335/7110367 - person Ido Kessler; 28.09.2020

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

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

Демо.

person Jarod42    schedule 08.08.2017
comment
Я предполагаю, что это будет подходящий ответ примерно в 2023 году. - person wcochran; 14.09.2020

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

//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());
}
person Vikramjit Roy    schedule 08.05.2018
comment
Так просто, но я никогда не думал об этом так! - person Zimano; 15.03.2019
comment
Пример кода неверен. v1.insert(v2.end()... использует итератор в v2, чтобы указать позицию в v1. - person David Stone; 06.07.2019
comment
Вы также можете использовать быструю замену. @DavidStone Я отредактировал его, чтобы можно было изменить порядок конкатенации. Можно ли добавить в начало вектора? - person qwr; 09.12.2019
comment
Вы можете вставить в начало, но это будет медленнее. Однако для истинной конкатенации порядок обычно имеет значение, так что это то, что вам нужно сделать. - person David Stone; 10.12.2019
comment
Мне не нравится этот ответ, потому что вы не вставляете v2 после v1 во всех случаях (без указания этого примечания). В противном случае ваш ответ может быть более полным, если вы добавите решение, которое сохранит конкатенацию в другом векторе, а не изменит один из них. - person Ben_LCDB; 30.09.2020

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

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;
person Daniel Giger    schedule 26.06.2019

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

v1.insert(v1.end(), v2.begin(), v2.end());
person Boris    schedule 08.08.2017
comment
Разве это не то же самое с ответом, данным Томом Риттером и Робертом Гэмблом в 2008 году? - person IgNite; 03.02.2020

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

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

person AlexT    schedule 06.05.2014
comment
Неужели тоже v1.erase(... кинуть нельзя? - person Class Skeleton; 12.10.2015
comment
insert уже занимается этим. Кроме того, этот вызов erase эквивалентен resize. - person Potatoswatter; 27.12.2016

Существует алгоритм 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;
}
person Pavan Chandaka    schedule 17.08.2019
comment
Я не думаю, что его проще использовать, чем std::vector::insert, но он имеет дело с чем-то другим: объединением двух диапазонов в новый диапазон против вставки одного вектора в конец другого. Стоит упомянуть в ответе? - person j b; 05.12.2019
comment
Ok. Я понял, чего ждут в ответе. Я добавлю. - person Pavan Chandaka; 26.10.2020

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

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]

person Stepan Yakovenko    schedule 11.11.2015
comment
Не знаю, почему это было отклонено. Возможно, это не самый эффективный способ сделать это, но он не неправильный и эффективный. - person leeor_net; 19.06.2016
comment
И это работает, если вы передаете один и тот же вектор в качестве обоих параметров, чтобы объединить вектор с самим собой. - person Jerry Jeremiah; 22.09.2020
comment
@leeo non const ref args для одного - person Yakk - Adam Nevraumont; 24.06.2021

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

person Ronald Souza    schedule 21.10.2019

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

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

person Daniel    schedule 08.03.2018
comment
Есть 1-й звонок 2-я перегрузка - person Yakk - Adam Nevraumont; 24.06.2021

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

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
person Vladimir U.    schedule 31.07.2018
comment
ИспользованиеT operator+(const T & a, const T & b) опасно, лучше использовать vector<T> operator+(const vector<T> & a, const vector<T> & b). - person Matthieu H; 13.12.2019

Я реализовал эту функцию, которая объединяет любое количество контейнеров, переходя от 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;
}
person Drew    schedule 11.07.2019
comment
Неправильно поступает с представлениями - person Yakk - Adam Nevraumont; 24.06.2021

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

person Aleph0    schedule 06.12.2018

Для контейнеров, которые предлагают push_back (string, vector, deque, ...):

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

а также

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

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

person Aroonalok    schedule 24.06.2021

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

person Jonathan Mee    schedule 22.02.2016

Вы можете сделать это с помощью предварительно реализованных алгоритмов 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()).

person rekkalmd    schedule 24.05.2020

Соедините два 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];
    }
person GobeRadJem32    schedule 08.06.2020
comment
кроме того, что он не работает, этот код в значительной степени неидиоматичен. По крайней мере, вы должны использовать auto итераторы вместо ручного индексирования. Вам не важно, какой индекс вы объединяете, только то, что это выполняется последовательно. - person Tarick Welling; 08.06.2020
comment
@TarickWelling Я не понимаю, почему вы сказали, что этот код не работает, не могли бы вы уточнить? - person Ben_LCDB; 30.09.2020
comment
Вы проверяли дату моего комментария? Вы исправили ошибки в своем коде, теперь это просто не идиоматично. - person Tarick Welling; 01.10.2020

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

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.

person GobeRadJem32    schedule 25.06.2020
comment
Ваше описание нечеткое (и бесполезное, извините). В противном случае ваш ответ может быть более полным, если вы добавите второе решение, которое сохранит конкатенацию в другом векторе, а не изменит один из них. - person Ben_LCDB; 30.09.2020

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

Метод 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());
person nvnhcmus    schedule 27.12.2016
comment
Что ваш ответ добавляет, чего еще не было в других ответах? - person Mat; 27.12.2016
comment
@Mat: жирные символы. - person marcv81; 24.03.2017
comment
Если после этого исходный вектор (ы) больше не нужен, может быть лучше использовать std::move_iterator, чтобы элементы перемещались, а не копировались. (см. en.cppreference.com/w/cpp/iterator/move_iterator) . - person tmlen; 23.02.2018
comment
Что такое setcapacity? Что такое function: ? - person L. F.; 29.03.2019
comment
@ L.F. Я думаю, он говорит о методе resize. - person Matthieu H; 13.12.2019

person    schedule
comment
Я бы только добавил код, чтобы сначала получить количество элементов, содержащихся в каждом векторе, и установить vector1 как самый большой. В противном случае вы делаете много ненужного копирования. - person Joe Pineda; 14.10.2008
comment
У меня вопрос. Будет ли это работать, если vector1 и vector2 являются одними и теми же векторами? - person Alexander Rafferty; 17.07.2011
comment
Если у вас есть объединение нескольких векторов в один, полезно ли сначала вызвать reserve для вектора назначения? - person Faheem Mitha; 05.02.2012
comment
@AlexanderRafferty: Только если vector1.capacity() >= 2 * vector1.size(). Что нетипично, если вы не позвонили std::vector::reserve(). В противном случае вектор будет перераспределен, что сделает недействительными итераторы, переданные как параметры 2 и 3. - person Drew Dormann; 22.06.2012
comment
@FaheemMitha: Поскольку аргументы insert являются векторами, он уже знает, сколько элементов впереди, и обработает это сам. Если мы вставляли другие вещи, такие как массив, было бы полезно сначала зарезервировать место. - person Aidin; 14.04.2014
comment
@ Эйдин, ясно. Спасибо за разъяснения. - person Faheem Mitha; 14.04.2014
comment
@Khaur: Это настолько ужасно, что в это трудно поверить. Для реализации очень легко обнаружить итераторы с произвольным доступом, вычислить размер и предварительно зарезервировать необходимое пространство. Я думаю, что MSFT делает это даже для прямых итераторов. - person Mooing Duck; 05.04.2016
comment
@MooingDuck Вы правы, я пропустил диспетчер и подумал, что версия итератора ввода применяется ко всем типам итераторов. Версия с прямым итератором делает гораздо больше. Спасибо, что указали на это, я удалил свой первоначальный комментарий, чтобы он не появлялся без вашего. - person Khaur; 14.04.2016
comment
Жаль, что в стандартной библиотеке нет более лаконичного выражения. .concat или += или что-то в этом роде - person nmr; 15.10.2016
comment
@nmr В C ++ это довольно лаконично. - person YSC; 08.11.2018
comment
Трудно получить обзор всех различных ответов на этот вопрос. Подход std::vector::insert также был опубликован в нескольких других ответах, но у него больше всего голосов, поэтому я спрошу / заявлю здесь: Использование insert должно иметь преимущество перед другими подходами, которые используют back_inserter, потому что insert потенциально может использовать memcpy в одном массиве, в то время как подходы, использующие back_inserter, должны перебирать вектор, который будет вставлен элемент за элементом. Я правильно понимаю? - person j00hi; 22.08.2019

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