Can someone explain why this vector erase operation isn't working properly?

Viewed 171
    vector<int> nums{1,2,3,0,0,0};
    
    for(int i = 0; i< nums.size(); i++){
        if(nums[i] == 0){
            nums.erase(nums.begin() + i);
        }
    }
    for(int i = 0; i< nums.size(); i++){
        cout << nums[i] << " ";
    }
    //I keep getting [1, 2, 3, 0]

I want to remove the zeros from the vector so that I only have 1,2,3 left over. However, the method I'm using seems to keep leaving one zero at the end. I've been at it for a while and I've played with the indexing but I can't seem to get it to work correctly. I'd appreciate help thanks.

3 Answers

Every time you erase from a vector the index of following elements decreases by 1. You need to account for this:

for(int i = 0; i< nums.size(); i++){
        if(nums[i] == 0){
            nums.erase(nums.begin() + i);
            --i; // <-- HERE
        }
    }

This is an O(n^2) operation. You can do this in O(n) like this:

nums.erase(std::remove(nums.begin(), nums.end(), 0),
           nums.end());

The vector erase function reduces the size of the vector. The last zero is not getting erased because you are erasing from the same vector whose size is getting checked in the for loop.

Erase-Remove has been covered, so here's another, but inferior, X-Y Answer. It's worth mentioning because it shows how to use erase's return value.

Use iterators.

vector<int> nums{1,2,3,0,0,0};

for(auto it = nums.begin(); it != nums.end(); ){
    if(*it == 0){
        it = nums.erase(it); // erase returns an iterator to the next element
                             // effectively it++ with the added benefit of it
                             // not being invalidated by removal from the vector
    }
    else {
        it++; // not removed? now we need to increment
    }
}
for(const auto & val: nums){
    cout << val << " ";
}
Related