2つstd::vector
のを連結するにはどうすればよいですか?
a + b
またはa.concat(b)
標準ライブラリに実装されていないのはなぜですか?おそらく、デフォルトの実装は最適ではないかもしれませんが、すべての配列の連結をマイクロ最適化する必要はありません
2つstd::vector
のを連結するにはどうすればよいですか?
a + b
またはa.concat(b)
標準ライブラリに実装されていないのはなぜですか?おそらく、デフォルトの実装は最適ではないかもしれませんが、すべての配列の連結をマイクロ最適化する必要はありません
回答:
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
reserve
最初に宛先ベクトルを呼び出すと役に立ちますか?
vector1.capacity() >= 2 * vector1.size()
。あなたが呼ばない限り、これは非定型ですstd::vector::reserve()
。そうでない場合はベクターがパラメータ2および3として渡されたイテレータを無効化、再割り当てされます
.concat
または+=
何か
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;
}
これは、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の新しい要素に転送されました。
std::move(src.begin(), src.end(), back_inserter(dest))
どう違いますか?
または、次のように使用できます。
std::copy(source.begin(), source.end(), std::back_inserter(destination));
std :: back_inserterの代わりに何かを使用して1つのタイプから別のタイプに変換できるため、このパターンは2つのベクトルにまったく同じタイプのものが含まれていない場合に役立ちます。
reserve
最初に電話をかけるのを止めるものはありません。std::copy
が便利な理由は、以外のものを使用したい場合ですback_inserter
。
C ++ 11では、ベクトルbをaに追加することをお勧めします。
std::move(b.begin(), b.end(), std::back_inserter(a));
ときa
とb
重なっていない、そしてb
もう使用する予定がありません。
insert
はより安全な古い方法に戻るべきです。
insert()
はmove_iterator
s とは異なりますか?もしそうなら、どうですか?
std::move
ほとんどの人はこの過負荷を知らないので、ここで話していることについてのメモを追加しました。それが改善であることを願っています。
私はすでに言及されているものを好む:
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());
}
std::
、のタイプa
がからのものstd
である場合にのみ追加されます。これは一般的な側面を無効にします。
あなたはvector :: insertを使うべきです
v1.insert(v1.end(), v2.begin(), v2.end());
一般的なパフォーマンスの向上 CONCATENATEのためには、ベクトルの大きさをチェックすることです。そして、小さい方を大きい方とマージ/挿入します。
//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());
}
v1.insert(v2.end()...
イテレータinto v2
を使用していますv1
。
強力な例外保証に関心がある場合(コピーコンストラクターが例外をスローできる場合):
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
ベクトル要素のmoveコンストラクターがスローできる場合、強力な保証付きの同様のものを一般に実装することはできません(可能性は低いですが、それでも)。
v1.erase(...
あまりにもスローしますか?
insert
すでにこれを処理します。また、このへの呼び出しerase
はと同等resize
です。
これをヘッダーファイルに追加します。
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]が含まれます
次に、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
。
+演算子用に独自のテンプレートを準備できます。
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)
です。使用することをお勧めします。
アルゴリズムがある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
が、それは別の何かを行います。他の終わりに1つのベクトルを挿入する対新しい範囲に二つの範囲をマージ。答えで言及する価値がありますか?
読み取り専用の目的で値の範囲を反復するだけの場合は、両方のベクトルをコピー(O(n))する代わりにプロキシ(O(1))にラップするので、すぐに確認できます。単一の連続したものとして。
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
「VecProxy」の実装や長所と短所など、詳細については、https: //stackoverflow.com/a/55838758/2379625を参照してください。
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
任意の数のコンテナーを連結するこの関数を実装しました。右辺値参照から移動し、それ以外の場合はコピーします
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;
}
あなたが探しているものがベクトルを作成後に別のものに追加する方法であるならば、あなた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>
のの連結を保持するためのコンテナである場合、次の条件に当てはまる場合は、より良いものがあるかもしれません。
vector
プリミティブが含まれています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
この解決策は少し複雑かもしれませんが、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;
}
大きなベクターの場合、コピーがないため、これは利点になる可能性があります。Generalizeを複数のコンテナーに簡単にコピーするためにも使用できます。
何らかの理由でboost::join(a,b,c)
、のようなものはありません。
ポリモーフィック型の使用のためのテンプレートを使用して、事前に実装された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;
}
さらに使用したくない場合は、2番目のベクトルをクリアできます(clear()
メソッド)。
正直に言うと、2つのベクターから別のベクターに要素をコピーするか、2つのベクターの1つだけを追加することで、2つのベクターをすばやく連結できます。それはあなたの目的に依存します。
方法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());
std::move_iterator
要素をコピーするのではなく移動するように使用することをお勧めします。(en.cppreference.com/w/cpp/iterator/move_iteratorを参照してください)。
setcapacity
?なにfunction:
?
resize
方法について話していると思います。