ฉันจะต่อสองstd::vector
s เข้าด้วยกันได้อย่างไร
a + b
หรือa.concat(b)
ในห้องสมุดมาตรฐาน? บางทีการใช้งานเริ่มต้นอาจไม่ดีนัก แต่การต่อข้อมูลอาเรย์ทุกอันไม่จำเป็นต้องปรับให้เหมาะสมขนาดเล็ก
ฉันจะต่อสองstd::vector
s เข้าด้วยกันได้อย่างไร
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;
}
สิ่งนี้จะไม่มีประสิทธิภาพมากขึ้นสำหรับตัวอย่างที่มี ints เนื่องจากการย้ายนั้นไม่มีประสิทธิภาพมากกว่าการคัดลอก แต่สำหรับโครงสร้างข้อมูลที่มีการย้ายที่ดีที่สุดจะสามารถหลีกเลี่ยงการคัดลอกสถานะที่ไม่จำเป็น:
#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 ถูกปล่อยให้อยู่ในสถานะที่ไม่ได้กำหนด แต่ปลอดภัยต่อการทำลายล้างและองค์ประกอบเดิมของมันจะถูกถ่ายโอนโดยตรงไปยังองค์ประกอบใหม่ของปลายทางในตอนท้าย
std::move(src.begin(), src.end(), back_inserter(dest))
อะไร?
ฉันจะใช้ฟังก์ชั่นแทรกบางอย่างเช่น:
vector<int> a, b;
//fill with data
b.insert(b.end(), a.begin(), a.end());
หรือคุณสามารถใช้:
std::copy(source.begin(), source.end(), std::back_inserter(destination));
รูปแบบนี้มีประโยชน์หากสองเวกเตอร์ไม่มีสิ่งเดียวกันประเภทเดียวกันเนื่องจากคุณสามารถใช้บางสิ่งแทน std :: back_inserter เพื่อแปลงจากประเภทหนึ่งไปเป็นอีกประเภทหนึ่ง
reserve
ก่อน เหตุผลที่บางครั้งก็เป็นประโยชน์คือถ้าคุณต้องการที่จะใช้สิ่งอื่นที่ไม่ใช่std::copy
back_inserter
ด้วย C ++ 11 ฉันต้องการที่จะต่อท้ายเวกเตอร์ b กับ a:
std::move(b.begin(), b.end(), std::back_inserter(a));
เมื่อใดa
และb
จะไม่ทับซ้อนกันและb
จะไม่ถูกใช้อีกต่อไป
นี่คือstd::move
จาก<algorithm>
ที่ไม่ปกติ จากstd::move
<utility>
insert
วิธีเดิมซึ่งปลอดภัยกว่า
insert()
กับmove_iterator
s หรือไม่? ถ้าเป็นเช่นนั้นได้อย่างไร
std::move
เรากำลังพูดถึงที่นี่เนื่องจากคนส่วนใหญ่ไม่ทราบว่าเกินพิกัดนี้ หวังว่ามันจะเป็นการปรับปรุง
std::vector<int> first;
std::vector<int> second;
first.insert(first.end(), second.begin(), second.end());
ฉันชอบหนึ่งที่กล่าวถึงแล้ว:
a.insert(a.end(), b.begin(), b.end());
แต่ถ้าคุณใช้ C ++ 11 มีวิธีทั่วไปมากกว่าหนึ่งวิธี:
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()...
กำลังใช้ iterator เข้าไปเพื่อระบุตำแหน่งในv2
v1
หากคุณต้องการให้เวกเตอร์เรียงต่อกันอย่างกระชับคุณสามารถโอเวอร์โหลด+=
โอเปอเรเตอร์ได้
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;
หากคุณสนใจในการรับประกันข้อยกเว้นที่แข็งแกร่ง (เมื่อตัวสร้างสำเนาสามารถโยนข้อยกเว้น):
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
โดยทั่วไปแล้วจะไม่สามารถนำไปใช้กับการรับประกันที่คล้ายกันได้หากตัวสร้างการเคลื่อนไหวขององค์ประกอบเวกเตอร์สามารถโยนได้ (ซึ่งไม่น่าเป็นไปได้ แต่ยังคงมีอยู่)
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
นี้ แต่ทำเพื่อสิ่งที่แตกต่าง: ผสานสองช่วงเป็นช่วงใหม่กับการแทรกเวกเตอร์หนึ่งตัวที่ส่วนท้ายของอีกอัน ควรพูดถึงคำตอบไหม?
หากเป้าหมายของคุณคือทำซ้ำในช่วงของค่าเพื่อวัตถุประสงค์ในการอ่านอย่างเดียวทางเลือกก็คือการห่อเวกเตอร์ทั้งสองรอบพร็อกซี (O (1)) แทนการคัดลอก (O (n)) ดังนั้นพวกเขาจะเห็นทันที เป็นหนึ่งเดียวที่ต่อเนื่องกัน
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
อ้างถึงhttps://stackoverflow.com/a/55838758/2379625สำหรับรายละเอียดเพิ่มเติมรวมถึงการใช้งาน 'VecProxy' เช่นเดียวกับข้อดีข้อเสีย
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
ฉันได้ใช้ฟังก์ชั่นนี้ซึ่งเชื่อมต่อจำนวนของคอนเทนเนอร์ใด ๆ ย้ายจากการอ้างอิง rvalue และการคัดลอกเป็นอย่างอื่น
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
หากสิ่งที่คุณกำลังมองหาคือที่เก็บของที่มีการต่อกันของสองตัวนี้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;
}
สำหรับเวกเตอร์ขนาดใหญ่นี่อาจเป็นข้อได้เปรียบเนื่องจากไม่มีการคัดลอก นอกจากนี้ยังสามารถใช้สำหรับการทำสำเนา generalizes ไปยังคอนเทนเนอร์มากกว่าหนึ่งคอนเทนเนอร์ได้อย่างง่ายดาย
ด้วยเหตุผลบางอย่างไม่มีอะไรเหมือนboost::join(a,b,c)
ซึ่งอาจสมเหตุสมผล
คุณสามารถทำได้ด้วยอัลกอริธึม STL ที่นำไปใช้ล่วงหน้าโดยใช้เทมเพลตสำหรับการใช้งานประเภท polymorphic
#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;
}
คุณสามารถล้างเวกเตอร์ที่สองหากคุณไม่ต้องการใช้เพิ่มเติม ( clear()
วิธีการ)
Concatenate สองstd::vector-s
กับวงในfor
std::vector
ตัวอย่าง:
std::vector <int> v1 {1, 2, 3};//declare vector1
std::vector <int> v2 {4, 5};//declare vector2
std::vector <int> suma;//declare vector suma
for(int i = 0; i < v1.size()-1;i++)//for loop 1
{
suma.push_back(v1[i]);
}
for(int i = 0; i< v2.size()-1;i++)/for loop 2
{
suma.push_back(v2[i]);
}
for(int i = 0; i < suma.size(); i++)//for loop 3-output
{
std::cout<<suma[i];
}
main()
เขียนโค้ดนี้ใน
for
ลูปผิด ดัชนีที่ถูกต้องในเวกเตอร์จาก 0 size()-1
ถึง คุณเงื่อนไขการเลิกห่วงจะต้องi < v1.size()
ใช้ไม่ได้<
<=
การใช้เงื่อนไขที่ไม่ถูกต้องเข้าถึงหน่วยความจำภายนอกคอนเทนเนอร์
auto
วนซ้ำแทนการสร้างดัชนีด้วยตนเอง คุณไม่แคร์ว่าดัชนีใดที่คุณต่อกันเท่านั้นที่จะเรียงตามลำดับ
size()-1
ในสภาวะวนรอบสองแบบ? นั่นข้ามองค์ประกอบเวกเตอร์สุดท้าย วงที่สามเป็นวงเดียวที่ถูกต้องในตอนนี้
ตามจริงแล้วคุณสามารถต่อเวกเตอร์สองตัวเข้าด้วยกันโดยคัดลอกองค์ประกอบจากเวกเตอร์สองตัวไปอีกอันหนึ่งหรือเพียงแค่ผนวกหนึ่งในสองเวกเตอร์! มันขึ้นอยู่กับเป้าหมายของคุณ
วิธีที่ 1:กำหนดขนาดเวกเตอร์ใหม่ด้วยผลรวมของขนาดเวกเตอร์ดั้งเดิมสองขนาด
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:ผนวกเวกเตอร์ A โดยการเพิ่ม / แทรกองค์ประกอบของเวกเตอร์ 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_iterator
เพื่อย้ายองค์ประกอบแทนที่จะคัดลอก (ดูen.cppreference.com/w/cpp/iterator/move_iterator )
setcapacity
อะไร คือfunction:
อะไร
resize
วิธีการ