Jawaban yang diberikan tidak benar-benar digabungkan. Mereka menambahkan salinan. Mungkin ada gunanya (untuk sudut pandang efisiensi) untuk membuat metode gabungan std :: vector, namun itu akan memerlukan beberapa berbagi canggih pengelolaan node dan itu mungkin mengapa itu belum dilakukan.
FauChristian
8
@ Fu christian: Tidak, mungkin tidak ada gunanya dari sudut pandang efisiensi. Memori vektor harus kontinu, sehingga apa yang Anda sarankan tidak mungkin. Jika Anda ingin "berbagi canggih pengelolaan node", dan jika Anda mengubah kelas vektor sedemikian rupa, Anda akan berakhir dengan deque. Bahkan kemudian sangat sulit untuk menggunakan kembali memori dengan cara yang disarankan, meskipun itu akan mulai menjadi sedikit lebih layak. Saya tidak berpikir ini sedang dilaksanakan. Hal utama adalah bahwa dalam pembagian node manajemen (deque) seperti itu, node akhir mungkin sebagian kosong.
Kue
4
@lecaruyer Anda menyadari bahwa Anda baru saja menandai pertanyaan yang diajukan dua tahun sebelumnya sebagai duplikat
eshirima
9
Apakah saya satu-satunya yang bertanya-tanya mengapa ini tidak diimplementasikan sebagai a + batau a.concat(b)di perpustakaan standar? Mungkin implementasi default akan suboptimal, tetapi setiap rangkaian array tidak perlu dioptimalkan secara mikro
oseiskar
9
evolusi selama bertahun-tahun, kelebihan-operator yang paling canggih dari semua bahasa utama, sistem templating yang menggandakan kompleksitas bahasa, namun jawabannya bukan v = v1 + v2;
Saya hanya akan menambahkan kode untuk pertama-tama mendapatkan jumlah elemen yang masing-masing vektor pegang, dan mengatur vector1 menjadi yang memegang terbesar. Jika Anda melakukan sebaliknya Anda melakukan banyak penyalinan yang tidak perlu.
Joe Pineda
34
Saya punya pertanyaan. Apakah ini akan berfungsi jika vector1 dan vector2 adalah vektor yang sama?
Alexander Rafferty
6
Jika Anda telah menyatukan beberapa vektor ke satu, apakah sebaiknya memanggil reservevektor tujuan terlebih dahulu?
Faheem Mitha
33
@AlexanderRafferty: Hanya jika 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.
Drew Dormann
28
Sayang sekali tidak ada ekspresi yang lebih ringkas di perpustakaan standar. .concatatau +=atau sesuatu
nmr
193
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"));return0;}
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()));return0;}
Setelah pindah, elemen src dibiarkan dalam keadaan tidak terdefinisi tetapi aman untuk dihancurkan, dan elemen sebelumnya dipindahkan langsung ke elemen baru dest pada akhirnya.
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.
metode salin bukan cara yang baik. Ini akan memanggil beberapa waktu push_back yang berarti bahwa jika banyak elemen harus dimasukkan ini bisa berarti beberapa realokasi. lebih baik menggunakan insert karena implementasi vektor dapat melakukan beberapa optimasi untuk menghindari realokasi. itu bisa menyimpan memori sebelum mulai menyalin
Yogesh Arora
7
@Yogesh: memang, tapi tidak ada yang menghentikan Anda menelepon reservedulu. Alasan std::copyyang terkadang bermanfaat adalah jika Anda ingin menggunakan sesuatu selain back_inserter.
Roger Lipscombe
Ketika Anda mengatakan "alokasi ganda", itu benar - tetapi jumlah alokasi adalah log terburuk (jumlah entri ditambahkan) - yang berarti bahwa biaya menambahkan entri adalah konstan dalam jumlah entri yang ditambahkan. (Pada dasarnya, jangan khawatir tentang hal itu kecuali membuat profil menunjukkan Anda memerlukan cadangan).
Martin Bonner mendukung Monica
Anda mungkin ingin menggunakan std :: transform untuk melakukan ini.
Perilaku tidak terdefinisi jika a sebenarnya adalah b (yang OK jika Anda tahu itu tidak akan pernah terjadi - tetapi perlu diperhatikan dalam kode tujuan umum).
Martin Bonner mendukung Monica
1
@ MartinBonner Terima kasih telah menyebutkan itu. Mungkin saya harus kembali ke insertcara lama yang lebih aman.
Deqing
15
Ah, std LAIN :: bergerak. Cukup membingungkan saat pertama kali Anda melihatnya.
xaxxon
1
Apakah ini berbeda insert()dengan dengan move_iterators? Jika ya, bagaimana caranya?
GPhilo
1
Saya telah menambahkan catatan tentang apa yang std::movekita bicarakan di sini, karena kebanyakan orang tidak tahu kelebihan ini. Semoga ini perbaikan.
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.
@Asu ADL hanya akan menambahkan std::jika jenis aberasal dari std, yang mengalahkan aspek generik.
Potatoswatter
Poin yang bagus. dalam hal ini vektor sehingga akan bekerja, tapi ya itu solusi yang lebih baik.
Asu
std :: begin () / end () ditambahkan untuk koleksi (seperti array) yang tidak memilikinya sebagai fungsi anggota. Tetapi array juga tidak memiliki fungsi anggota insert (), dan menyebut pertanyaan "Apakah ada koleksi dengan insert () tetapi tanpa begin () (yang berfungsi dengan std :: begin ())?"
James Curran
15
Dengan rentang v3 , Anda mungkin memiliki rangkaian malas :
Sangat sederhana, namun saya tidak pernah berpikir seperti itu!
Zimano
2
Kode sampel salah. v1.insert(v2.end()...menggunakan iterator ke v2untuk menentukan posisi dalam v1.
David Stone
Anda juga dapat menggunakan swap cepat. @ Davidvidone saya mengeditnya sehingga urutan concat dapat diubah. Apakah mungkin untuk menambahkan awal vektor?
qwr
Anda dapat menyisipkan ke awal, tetapi itu akan lebih lambat. Namun, untuk benar-benar "menyatukan", urutan biasanya penting, jadi itulah yang perlu Anda lakukan.
David Stone
7
Jika Anda ingin dapat menyatukan vektor secara ringkas, Anda dapat membebani +=operator.
Mirip append_movedengan jaminan yang kuat tidak dapat diterapkan secara umum jika konstruktor elemen bergerak dapat melempar (yang tidak mungkin tetapi tetap).
Saya tidak berpikir itu lebih mudah untuk digunakan daripada 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?
jb
4
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.
Meskipun potongan kode ini dapat menyelesaikan masalah, itu tidak menjelaskan mengapa atau bagaimana ia menjawab pertanyaan. Harap sertakan penjelasan untuk kode Anda , karena itu sangat membantu untuk meningkatkan kualitas posting Anda. Penanda / pengulas: Untuk jawaban hanya kode seperti ini, downvote, jangan hapus! (Catatan: Jawaban ini mungkin sebenarnya cukup sederhana untuk membuat penjelasan, dan dengan demikian menurunkan, tidak perlu. Anda mungkin masih ingin menambahkan penjelasan untuk mencegah lebih banyak bendera NAA / VLQ.)
Scott Weldon
2
Saya telah mengimplementasikan fungsi ini yang menggabungkan sejumlah kontainer, bergerak dari rvalue-reference dan menyalin sebaliknya
namespaceinternal{// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if// appropriatetemplate<typenameTarget,typenameHead,typename...Tail>voidAppendNoReserve(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");ifconstexpr(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));}ifconstexpr(sizeof...(Tail)>0){AppendNoReserve(target, std::forward<Tail>(tail)...);}}template<typenameHead,typename...Tail>size_tTotalSize(constHead& head,constTail&... tail){ifconstexpr(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<typenameHead,typename...Tail>autoConcatenate(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:
Anda vectormengandung primitif
Primitif Anda yang terkandung berukuran 32-bit atau lebih kecil
Anda menginginkan sebuah constwadah
Jika 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:
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 iteratorfor(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.
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());
Apa yang ditambahkan jawaban Anda yang belum disediakan di jawaban lain?
Mat
13
@Mat: Karakter tebal.
marcv81
Jika vektor asli tidak diperlukan lagi setelahnya, mungkin lebih baik digunakan std::move_iteratoragar elemen dipindahkan daripada disalin. (lihat en.cppreference.com/w/cpp/iterator/move_iterator ).
tmlen
Apa setcapacity? Apa function: ?
LF
@ Jika saya pikir dia berbicara tentang resizemetode ini.
a + b
ataua.concat(b)
di perpustakaan standar? Mungkin implementasi default akan suboptimal, tetapi setiap rangkaian array tidak perlu dioptimalkan secara mikroJawaban:
sumber
reserve
vektor tujuan terlebih dahulu?vector1.capacity() >= 2 * vector1.size()
. Yang tidak biasa kecuali Anda sudah meneleponstd::vector::reserve()
. Kalau tidak, vektor akan realokasi, membatalkan iterator yang dilewatkan sebagai parameter 2 dan 3..concat
atau+=
atau sesuatuJika Anda menggunakan C ++ 11, dan ingin memindahkan elemen daripada hanya menyalinnya, Anda dapat menggunakannya
std::move_iterator
bersama dengan menyisipkan (atau menyalin):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:
Setelah pindah, elemen src dibiarkan dalam keadaan tidak terdefinisi tetapi aman untuk dihancurkan, dan elemen sebelumnya dipindahkan langsung ke elemen baru dest pada akhirnya.
sumber
std::move(src.begin(), src.end(), back_inserter(dest))
?Saya akan menggunakan fungsi insert , seperti:
sumber
Atau Anda bisa menggunakan:
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.
sumber
reserve
dulu. Alasanstd::copy
yang terkadang bermanfaat adalah jika Anda ingin menggunakan sesuatu selainback_inserter
.Dengan C ++ 11, saya lebih suka mengikuti untuk menambahkan vektor b ke:
kapan
a
danb
tidak tumpang tindih, danb
tidak akan digunakan lagi.Ini
std::move
dari<algorithm>
, tidak biasastd::move
dari<utility>
.sumber
insert
cara lama yang lebih aman.insert()
dengan denganmove_iterator
s? Jika ya, bagaimana caranya?std::move
kita bicarakan di sini, karena kebanyakan orang tidak tahu kelebihan ini. Semoga ini perbaikan.sumber
Saya lebih suka yang sudah disebutkan:
Tetapi jika Anda menggunakan C ++ 11, ada satu lagi cara umum:
Juga, bukan bagian dari pertanyaan, tetapi disarankan untuk digunakan
reserve
sebelum menambahkan untuk kinerja yang lebih baik. Dan jika Anda menggabungkan vektor dengan dirinya sendiri, tanpa menyimpannya gagal, maka Anda harus selalu melakukannyareserve
.Jadi pada dasarnya yang Anda butuhkan:
sumber
std::
disimpulkan melalui pencarian argumen-dependen .end(a)
akan cukup.std::
jika jenisa
berasal daristd
, yang mengalahkan aspek generik.Dengan rentang v3 , Anda mungkin memiliki rangkaian malas :
Demo .
sumber
Anda harus menggunakan vector :: insert
sumber
Peningkatan kinerja umum untuk concatenate adalah untuk memeriksa ukuran vektor. Dan gabungkan / masukkan yang lebih kecil dengan yang lebih besar.
sumber
v1.insert(v2.end()...
menggunakan iterator kev2
untuk menentukan posisi dalamv1
.Jika Anda ingin dapat menyatukan vektor secara ringkas, Anda dapat membebani
+=
operator.Maka Anda dapat menyebutnya seperti ini:
sumber
Jika Anda tertarik dengan jaminan pengecualian yang kuat (ketika copy constructor dapat memberikan pengecualian):
Mirip
append_move
dengan jaminan yang kuat tidak dapat diterapkan secara umum jika konstruktor elemen bergerak dapat melempar (yang tidak mungkin tetapi tetap).sumber
v1.erase(...
melempar juga?insert
sudah menangani ini. Selain itu, panggilan keerase
ini setara dengan aresize
.Tambahkan yang ini ke file header Anda:
dan gunakan seperti ini:
r akan mengandung [1,2,62]
sumber
Berikut ini adalah solusi tujuan umum menggunakan semantik C ++ 11 move:
Perhatikan bagaimana ini berbeda dari
append
ing kevector
.sumber
Anda dapat menyiapkan templat Anda sendiri untuk + operator:
Hal berikutnya - cukup gunakan +:
Contoh ini memberikan output:
sumber
T operator+(const T & a, const T & b)
berbahaya, lebih baik digunakanvector<T> operator+(const vector<T> & a, const vector<T> & b)
.Ada algoritma
std::merge
dari C ++ 17 , yang sangat mudah digunakan,Di bawah ini adalah contohnya:
sumber
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.
Lihat https://stackoverflow.com/a/55838758/2379625 untuk rincian lebih lanjut, termasuk implementasi 'VecProxy' serta pro & kontra.
sumber
sumber
Saya telah mengimplementasikan fungsi ini yang menggabungkan sejumlah kontainer, bergerak dari rvalue-reference dan menyalin sebaliknya
sumber
Jika yang Anda cari adalah cara untuk menambahkan vektor ke vektor lain setelah pembuatan,
vector::insert
adalah taruhan terbaik Anda, seperti yang telah dijawab beberapa kali, misalnya:Sayangnya tidak ada cara untuk membangun
const vector<int>
, karena di atas Anda harus membangun dan kemudianinsert
.Jika yang Anda cari sebenarnya adalah wadah untuk mengadakan pertemuan kedua
vector<int>
, mungkin ada sesuatu yang lebih baik tersedia bagi Anda, jika:vector
mengandung primitifconst
wadahJika semua di atas benar, saya sarankan menggunakan
basic_string
yangchar_type
cocok dengan ukuran primitif yang terkandung di dalam Andavector
. Anda harus memasukkanstatic_assert
dalam kode Anda untuk memvalidasi ukuran ini tetap konsisten:Dengan memegang ini benar Anda hanya dapat melakukan:
Untuk informasi lebih lanjut tentang perbedaan antara
string
danvector
Anda dapat melihat di sini: https://stackoverflow.com/a/35558008/2642059Untuk contoh langsung dari kode ini Anda dapat melihat di sini: http://ideone.com/7Iww3I
sumber
Solusi ini mungkin agak rumit, tetapi
boost-range
juga memiliki beberapa hal bagus untuk ditawarkan.Seringkali niat adalah untuk menggabungkan vektor
a
danb
hanya mengulanginya melakukan beberapa operasi. Dalam hal ini, adajoin
fungsi sederhana yang konyol .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.sumber
Anda dapat melakukannya dengan algoritma STL yang telah diimplementasikan menggunakan template untuk penggunaan tipe polimorfik.
Anda dapat menghapus vektor kedua jika Anda tidak ingin menggunakannya lebih lanjut (
clear()
metode).sumber
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.
Metode 2: Tambahkan vektor A dengan menambahkan / memasukkan elemen vektor B.
sumber
std::move_iterator
agar elemen dipindahkan daripada disalin. (lihat en.cppreference.com/w/cpp/iterator/move_iterator ).setcapacity
? Apafunction:
?resize
metode ini.