Bagaimana saya menggabungkan dua std::vectors?
a + batau a.concat(b)di perpustakaan standar? Mungkin implementasi default akan suboptimal, tetapi setiap rangkaian array tidak perlu dioptimalkan secara mikro
Bagaimana saya menggabungkan dua std::vectors?
a + batau a.concat(b)di perpustakaan standar? Mungkin implementasi default akan suboptimal, tetapi setiap rangkaian array tidak perlu dioptimalkan secara mikro
Jawaban:
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
reservevektor tujuan terlebih dahulu?
vector1.capacity() >= 2 * vector1.size(). Yang tidak biasa kecuali Anda sudah menelepon std::vector::reserve(). Kalau tidak, vektor akan realokasi, membatalkan iterator yang dilewatkan sebagai parameter 2 dan 3.
.concatatau +=atau sesuatu
Jika Anda menggunakan C ++ 11, dan ingin memindahkan elemen daripada hanya menyalinnya, Anda dapat menggunakannya std::move_iteratorbersama dengan menyisipkan (atau menyalin):
#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;
}
Ini tidak akan lebih efisien untuk contoh dengan int, karena memindahkannya tidak lebih efisien daripada menyalinnya, tetapi untuk struktur data dengan gerakan yang dioptimalkan, ia dapat menghindari menyalin keadaan yang tidak perlu:
#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;
}
Setelah pindah, elemen src dibiarkan dalam keadaan tidak terdefinisi tetapi aman untuk dihancurkan, dan elemen sebelumnya dipindahkan langsung ke elemen baru dest pada akhirnya.
std::move(src.begin(), src.end(), back_inserter(dest))?
Saya akan menggunakan fungsi insert , seperti:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
Atau Anda bisa menggunakan:
std::copy(source.begin(), source.end(), std::back_inserter(destination));
Pola ini berguna jika kedua vektor tidak mengandung jenis yang persis sama, karena Anda dapat menggunakan sesuatu daripada std :: back_inserter untuk mengonversi dari satu jenis ke yang lain.
reservedulu. Alasan std::copyyang terkadang bermanfaat adalah jika Anda ingin menggunakan sesuatu selain back_inserter.
Dengan C ++ 11, saya lebih suka mengikuti untuk menambahkan vektor b ke:
std::move(b.begin(), b.end(), std::back_inserter(a));
kapan adan btidak tumpang tindih, dan btidak akan digunakan lagi.
Ini std::movedari <algorithm>, tidak biasa std::move dari <utility>.
insertcara lama yang lebih aman.
insert()dengan dengan move_iterators? Jika ya, bagaimana caranya?
std::movekita bicarakan di sini, karena kebanyakan orang tidak tahu kelebihan ini. Semoga ini perbaikan.
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
Saya lebih suka yang sudah disebutkan:
a.insert(a.end(), b.begin(), b.end());
Tetapi jika Anda menggunakan C ++ 11, ada satu lagi cara umum:
a.insert(std::end(a), std::begin(b), std::end(b));
Juga, bukan bagian dari pertanyaan, tetapi disarankan untuk digunakan reservesebelum menambahkan untuk kinerja yang lebih baik. Dan jika Anda menggabungkan vektor dengan dirinya sendiri, tanpa menyimpannya gagal, maka Anda harus selalu melakukannya reserve.
Jadi pada dasarnya yang Anda butuhkan:
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::jika jenis aberasal dari std, yang mengalahkan aspek generik.
Anda harus menggunakan vector :: insert
v1.insert(v1.end(), v2.begin(), v2.end());
Peningkatan kinerja umum untuk concatenate adalah untuk memeriksa ukuran vektor. Dan gabungkan / masukkan yang lebih kecil dengan yang lebih besar.
//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()...menggunakan iterator ke v2untuk menentukan posisi dalam v1.
Jika Anda ingin dapat menyatukan vektor secara ringkas, Anda dapat membebani +=operator.
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;
}
Maka Anda dapat menyebutnya seperti ini:
vector1 += vector2;
Jika Anda tertarik dengan jaminan pengecualian yang kuat (ketika copy constructor dapat memberikan pengecualian):
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;
}
}
Mirip append_movedengan jaminan yang kuat tidak dapat diterapkan secara umum jika konstruktor elemen bergerak dapat melempar (yang tidak mungkin tetapi tetap).
v1.erase(...melempar juga?
insertsudah menangani ini. Selain itu, panggilan ke eraseini setara dengan a resize.
Tambahkan yang ini ke file header Anda:
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;
}
dan gunakan seperti ini:
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 akan mengandung [1,2,62]
Berikut ini adalah solusi tujuan umum menggunakan semantik C ++ 11 move:
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);
}
Perhatikan bagaimana ini berbeda dari appending ke vector.
Anda dapat menyiapkan templat Anda sendiri untuk + operator:
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;
}
Hal berikutnya - cukup gunakan +:
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
Contoh ini memberikan output:
1 2 3 4 5 6 7 8
T operator+(const T & a, const T & b)berbahaya, lebih baik digunakan vector<T> operator+(const vector<T> & a, const vector<T> & b).
Ada algoritma std::mergedari C ++ 17 , yang sangat mudah digunakan,
Di bawah ini adalah contohnya:
#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, tetapi itu untuk sesuatu yang berbeda: menggabungkan dua rentang ke dalam rentang baru vs memasukkan satu vektor di ujung yang lain. Layak disebutkan dalam jawabannya?
Jika tujuan Anda hanya untuk mengulangi rentang nilai untuk tujuan hanya-baca, alternatifnya adalah membungkus kedua vektor di sekitar proksi (O (1)) alih-alih menyalinnya (O (n)), sehingga mereka segera terlihat sebagai satu, yang berdekatan.
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
Lihat https://stackoverflow.com/a/55838758/2379625 untuk rincian lebih lanjut, termasuk implementasi 'VecProxy' serta pro & kontra.
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
Saya telah mengimplementasikan fungsi ini yang menggabungkan sejumlah kontainer, bergerak dari rvalue-reference dan menyalin sebaliknya
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;
}
Jika yang Anda cari adalah cara untuk menambahkan vektor ke vektor lain setelah pembuatan, vector::insertadalah taruhan terbaik Anda, seperti yang telah dijawab beberapa kali, misalnya:
vector<int> first = {13};
const vector<int> second = {42};
first.insert(first.end(), second.cbegin(), second.cend());
Sayangnya tidak ada cara untuk membangun const vector<int>, karena di atas Anda harus membangun dan kemudian insert.
Jika yang Anda cari sebenarnya adalah wadah untuk mengadakan pertemuan kedua vector<int>, mungkin ada sesuatu yang lebih baik tersedia bagi Anda, jika:
vectormengandung primitifconstwadahJika semua di atas benar, saya sarankan menggunakan basic_stringyang char_typecocok dengan ukuran primitif yang terkandung di dalam Anda vector. Anda harus memasukkan static_assertdalam kode Anda untuk memvalidasi ukuran ini tetap konsisten:
static_assert(sizeof(char32_t) == sizeof(int));
Dengan memegang ini benar Anda hanya dapat melakukan:
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
Untuk informasi lebih lanjut tentang perbedaan antara stringdan vectorAnda dapat melihat di sini: https://stackoverflow.com/a/35558008/2642059
Untuk contoh langsung dari kode ini Anda dapat melihat di sini: http://ideone.com/7Iww3I
Solusi ini mungkin agak rumit, tetapi boost-rangejuga memiliki beberapa hal bagus untuk ditawarkan.
#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;
}
Seringkali niat adalah untuk menggabungkan vektor adan bhanya mengulanginya melakukan beberapa operasi. Dalam hal ini, ada joinfungsi sederhana yang konyol .
#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;
}
Untuk vektor besar ini mungkin menguntungkan, karena tidak ada penyalinan. Dapat juga digunakan untuk menyalin generalisasi dengan mudah ke lebih dari satu wadah.
Untuk beberapa alasan tidak ada yang seperti itu boost::join(a,b,c), yang bisa masuk akal.
Anda dapat melakukannya dengan algoritma STL yang telah diimplementasikan menggunakan template untuk penggunaan tipe polimorfik.
#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;
}
Anda dapat menghapus vektor kedua jika Anda tidak ingin menggunakannya lebih lanjut ( clear()metode).
Sejujurnya, Anda dapat dengan cepat menggabungkan dua vektor dengan menyalin elemen dari dua vektor ke vektor lainnya atau hanya menambahkan satu dari dua vektor !. Itu tergantung pada tujuan Anda.
Metode 1: Tetapkan vektor baru dengan ukurannya adalah jumlah dari dua ukuran vektor asli.
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
Metode 2: Tambahkan vektor A dengan menambahkan / memasukkan elemen vektor 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());
std::move_iteratoragar elemen dipindahkan daripada disalin. (lihat en.cppreference.com/w/cpp/iterator/move_iterator ).
setcapacity? Apa function: ?
resizemetode ini.