web-dev-qa-db-ja.com

2つのstd ::ベクトルを連結する

2つのstd::vectorを連結する方法

574
yigal
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
632
Robert Gamble

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")
    );

  return 0;
}

これは、intを使った例では、それらをコピーするよりも効率的ではないのでより効率的ではないでしょう。

#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の新しい要素に直接転送された。

148
Alex

insert関数 を使います。

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

またはあなたが使用することができます:

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

このパターンは、2つのベクトルがまったく同じ種類のものを含まない場合に便利です。これは、std :: back_inserterの代わりに何かを使用して、一方の型から他方の型に変換できるためです。

75
Roger Lipscombe

C++ 11では、ベクトルbをaに追加するのが望ましいです。

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

abがオーバーラップしておらず、bがもう使用されない場合。


これはstd::move<algorithm> であり、std::move 通常 <utility> ではありません。

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

first.insert(first.end(), second.begin(), second.end());
31
James Curran

私はすでに言及されているものを好む:

a.insert(a.end(), b.begin(), b.end());

しかし、C++ 11を使用している場合は、もう1つ一般的な方法があります。

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

vector :: insert を使うべきです

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

range v3 では、 lazy の連結が可能です。

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

デモ

9
Jarod42

一般的なパフォーマンスの向上 連結の場合、/はベクトルのサイズをチェックすることです。そして小さい方のものと大きい方のものをマージ/挿入します。

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

あなたが強い例外保証に興味があるならば(コピーコンストラクタが例外を投げることができるとき):

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

Vector要素のmoveコンストラクタがスローすることができる場合(これはほとんどありませんがそれでもまだ)、強力な保証付きの同様のappend_moveは一般に実装できません。

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

これは、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とどう違うかに注意してください。

3
Daniel

これをヘッダファイルに追加してください。

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]を含みます

3

+演算子用に独自のテンプレートを用意することができます。

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
1
Vladimir U.

ベクトルを簡潔に連結できるようにしたい場合は、+=演算子をオーバーロードできます。

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;
1
Daniel Giger

この解決法は少し複雑かもしれませんが、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;
}

多くの人の意図は、ベクトルabを組み合わせることで、何らかの操作を行ってそれを繰り返すことです。この場合、ばかげて単純な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)のようなものは何もありません。

0
Aleph0

正直に言うと、2つのベクトルから別の要素に要素をコピーすることによって2つのベクトルを高速に連結することも、2つのベクトルのうちの1つだけを追加することもできます。それはあなたの目的によります。

方法1: 新しいサイズのベクトルを元のサイズの2つのサイズの合計にする。

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: /ベクトルBの要素を追加/挿入して、ベクトルAを追加する。

// 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());
0
nvnhcmus

あなたが探しているものが作成後に別のものにベクトルを追加する方法である場合、 vector::insert は何度か答えられたように、あなたの最善の策です。例えば:

vector<int> first = {13};
const vector<int> second = {42};

first.insert(first.end(), second.cbegin(), second.cend());

悲しいことに、const vector<int>を構築する方法はありません。上記のようにinsertを構築しなければなりません。


あなたが実際に探しているものがこれら2つのvector<int>の連結を保持するコンテナであるならば、あなたにとってより利用可能な何かがあるかもしれません、:

  1. あなたのvectorはプリミティブを含んでいます
  2. 含まれているプリミティブのサイズが32ビット以下
  3. constコンテナが欲しい

上記がすべて当てはまる場合は、 basic_string whoの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());

stringvectorの違いの詳細については、こちらを参照してください。 https://stackoverflow.com/a/35558008/2642059

このコードの実際の例については、こちらをご覧ください。 http://ideone.com/7Iww3I

0
Jonathan Mee

任意の数のコンテナを連結し、右辺値参照から移動し、そうでなければコピーするこの関数を実装しました

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;
}
0
Drew

アルゴリズムがあります std::merge fromC++ 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;
}
0
Pavan Chandaka