ฉันมี std :: vector <int> และฉันต้องการลบองค์ประกอบ n'th ฉันจะทำอย่างไร
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
ฉันมี std :: vector <int> และฉันต้องการลบองค์ประกอบ n'th ฉันจะทำอย่างไร
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
คำตอบ:
หากต้องการลบองค์ประกอบเดียวคุณสามารถทำได้:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);
หรือหากต้องการลบมากกว่าหนึ่งองค์ประกอบในคราวเดียว:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);
operator+
จะไม่ได้กำหนดจำเป็นสำหรับ iterators ประเภทภาชนะอื่น ๆ เช่นlist<T>::iterator
(คุณไม่สามารถทำlist.begin() + 2
บนstd::list
คุณจะต้องใช้std::advance
สำหรับที่)
std::find_if
เมธอดการลบบน std :: vector มากเกินไปดังนั้นจึงอาจมีความชัดเจนในการโทร
vec.erase(vec.begin() + index);
เมื่อคุณต้องการลบองค์ประกอบเดียว
vec.begin()
ซึ่งถูกต้อง
vec.erase(0)
ใช้งานไม่ได้ แต่vec.erase(vec.begin()+0)
(หรือไม่มี +0) มิฉะนั้นฉันจะไม่เรียกฟังก์ชันที่ตรงกันซึ่งเป็นสาเหตุที่ฉันมาที่นี่
vec.erase(0)
จริง ๆ แล้วอาจทำการรวบรวมหาก0
ตีความได้ว่าเป็นค่าคงที่ตัวชี้โมฆะ ...
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
ฉันไม่ได้บอกว่ามันดีกว่าเพียงแค่ถามจากความสนใจส่วนตัวและเพื่อให้ได้ผลลัพธ์ที่ดีที่สุดคำถามนี้จะได้รับ
vector<T>::iterator
เป็นตัววนซ้ำการเข้าถึงแบบสุ่มรุ่นของคุณจึงใช้ได้และอาจชัดเจนขึ้นเล็กน้อย แต่เวอร์ชันที่ Max โพสต์ควรใช้งานได้ดีถ้าคุณเปลี่ยนคอนเทนเนอร์ไปเป็นอีกอันที่ไม่รองรับการเข้าถึงแบบวนซ้ำ
erase
วิธีการจะนำมาใช้ในสองวิธี
การลบองค์ประกอบเดียว:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
การลบช่วงขององค์ประกอบ:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
ที่จริงแล้วerase
ฟังก์ชั่นนี้ใช้งานได้สองโปรไฟล์:
การลบองค์ประกอบเดียว
iterator erase (iterator position);
การลบช่วงขององค์ประกอบ
iterator erase (iterator first, iterator last);
เนื่องจาก std :: vec.begin () ทำเครื่องหมายจุดเริ่มต้นของคอนเทนเนอร์และถ้าเราต้องการลบองค์ประกอบ ith ในเวกเตอร์ของเราเราสามารถใช้:
vec.erase(vec.begin() + index);
หากคุณดูอย่างใกล้ชิด vec.begin () เป็นเพียงตัวชี้ไปยังตำแหน่งเริ่มต้นของเวกเตอร์ของเราและการเพิ่มค่าของ i เพื่อเพิ่มตัวชี้ไปยังตำแหน่ง i ดังนั้นเราสามารถเข้าถึงตัวชี้ไปยังองค์ประกอบ ith แทน:
&vec[i]
ดังนั้นเราสามารถเขียน:
vec.erase(&vec[i]); // To delete the ith element
หากคุณมีเวกเตอร์ที่ไม่มีการเรียงลำดับคุณสามารถใช้ประโยชน์จากความจริงที่ว่ามันไม่มีการจัดเรียงและใช้สิ่งที่ฉันเห็นจาก Dan Higgins ที่ CPPCON
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
เนื่องจากลำดับของรายการไม่สำคัญเพียงนำองค์ประกอบสุดท้ายในรายการและคัดลอกที่ด้านบนสุดของรายการที่คุณต้องการลบจากนั้นป๊อปอัพและลบรายการสุดท้าย
iterator + index
จะให้ตำแหน่งตัววนซ้ำกลับคืนที่ดัชนีนั้นซึ่งไม่เป็นความจริงสำหรับคอนเทนเนอร์ตัววนซ้ำทั้งหมด นอกจากนี้ยังมีความซับซ้อนคงที่แทนที่จะเป็นเชิงเส้นโดยใช้ประโยชน์จากตัวชี้หลัง
unordered_remove
และunordered_remove_if
…เว้นแต่จะเป็นและฉันพลาดมันไปซึ่งเกิดขึ้นบ่อยขึ้นทุกวัน :)
std::remove
reorders ภาชนะเพื่อให้องค์ประกอบทั้งหมดจะถูกลบออกอยู่ที่ท้ายที่สุดไม่จำเป็นต้องทำด้วยตนเองเช่นนี้ถ้าคุณกำลังใช้ C ++ 17
std::remove
ช่วยได้อย่างไร cppreference อ้างว่าแม้ใน C ++ 17 remove
โอเวอร์โหลดทั้งหมดต้องการเพรดิเคตและไม่มีการทำดัชนี
หากคุณทำงานกับเวกเตอร์ขนาดใหญ่ (ขนาด> 100,000) และต้องการลบองค์ประกอบจำนวนมากฉันขอแนะนำให้ทำสิ่งนี้:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
รหัสใช้ตัวเลขทุกตัวเป็น vec ซึ่งไม่สามารถหารด้วย 3 และคัดลอกไปยัง vec2 หลังจากนั้นก็คัดลอก vec2 ใน vec มันค่อนข้างเร็ว ในการประมวลผลองค์ประกอบ 20,000,000 องค์ประกอบอัลกอริทึมนี้ใช้เวลาเพียง 0.8 วินาที!
ฉันทำสิ่งเดียวกันกับวิธีการลบและมันใช้เวลานานมาก:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
ในการลบองค์ประกอบให้ใช้วิธีดังต่อไปนี้:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
สำหรับภาพรวมที่กว้างขึ้นคุณสามารถเยี่ยมชม: http://www.cplusplus.com/reference/vector/vector/erase/
ฉันแนะนำให้อ่านเพราะฉันเชื่อว่านั่นคือสิ่งที่คุณกำลังมองหา https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
ถ้าคุณใช้เป็นตัวอย่าง
vec.erase(vec.begin() + 1, vec.begin() + 3);
คุณจะลบองค์ประกอบที่ n ของเวกเตอร์ แต่เมื่อคุณลบองค์ประกอบที่สององค์ประกอบอื่น ๆ ของเวกเตอร์จะถูกเลื่อนและขนาดเวกเตอร์จะเป็น -1 นี่อาจเป็นปัญหาหากคุณวนซ้ำผ่านเวกเตอร์เนื่องจากขนาดเวกเตอร์ () ลดลง หากคุณมีปัญหาเช่นนี้ให้ลิงค์แนะนำให้ใช้อัลกอริทึมที่มีอยู่ในห้องสมุด C ++ มาตรฐาน และ "ลบ" หรือ "remove_if"
หวังว่านี่จะช่วยได้
คำตอบก่อนหน้านี้คิดว่าคุณมักจะมีดัชนีลงนาม น่าเศร้าที่std::vector
ใช้size_type
สำหรับการจัดทำดัชนีและdifference_type
เลขคณิตตัววนซ้ำดังนั้นจึงไม่ทำงานร่วมกันหากคุณเปิดใช้งาน "-Wconversion" และเพื่อน นี่เป็นอีกวิธีหนึ่งในการตอบคำถามในขณะที่สามารถจัดการได้ทั้งที่ลงชื่อและไม่ได้ลงชื่อ:
เพื่อลบ:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
ที่จะใช้:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
นี่คืออีกวิธีหนึ่งในการทำเช่นนี้หากคุณต้องการลบองค์ประกอบโดยการค้นหาสิ่งนี้ด้วยค่าของมันในเวกเตอร์คุณเพียงแค่ต้องทำสิ่งนี้บนเวกเตอร์
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
มันจะลบค่าของคุณจากที่นี่ ขอบคุณ
แล้วเรื่องนี้ล่ะ
void squeeze(vector<int> &v)
{
int j = 0;
for (int i = 1; i < v.size(); i++)
if (v[i] != v[j] && ++j != i)
v[j] = v[i];
v.resize(j + 1);
}
วิธีที่เร็วที่สุด (สำหรับการแข่งขันการเขียนโปรแกรมตามเวลาที่ซับซ้อน () = คงที่)
สามารถลบรายการ 100M ใน 1 วินาที
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
และวิธีที่อ่านได้มากที่สุด:
vec.erase(vec.begin() + pos);
vector<int>::iterator
ไม่จำเป็นต้องเหมือนกับint *