Объединение двух 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<

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