Erasing vector elements using a loop

How to use a for loop to erase elements from a vector by its index? I get an error out of range. I have an example code below.

 vector<int> to_erase = {0, 1, 2}; 
 vector<int> data     = {3, 3, 3, 3};

 for(int i = 0; i < to_erase.size(); i++) {

    data.erase(data.begin() + to_erase[i]);
 }

I think this is because the size of my vector decreases with each iteration, so it cannot access index 2.

+4
source share
4 answers

You usually used erase-remove idiom to efficiently remove several elements from a vector (erasing them one by one is usually less effective and, as you saw, are not always trivial). In its most general form, the idiom is as follows:

data.erase(remove_algorithm(begin(data), end(data)), end(data));

remove_algorithm , :

data.erase(
    remove_indices(begin(data), end(data), begin(to_erase), end(to_erase)),
    end(data));

, . 1:

template <typename It, typename It2>
auto remove_indices(It begin, It end, It2 idx_b, It2 idx_e) -> It {
    using idx_t = typename std::iterator_traits<It2>::value_type;
    std::sort(idx_b, idx_e, std::greater<idx_t>{});

    for (; idx_b != idx_e; ++idx_b) {
        auto pos = begin + *idx_b;
        std::move(std::next(pos), end--, pos);
    }
    return end;
}

, . . ( ) ( ) . ( , ).

Live code


1 * Ahem * .

+6

, , probalby . , , , . ( , . , ( ) . , - :

data.resize(data.size() - reverse_counter);

int pos = data.size() - reverse_counter;
data.erease(data.begin()+pos, data.end();

sudo, .

, , . - : http://www.cplusplus.com/reference/vector/vector/erase/

0

, ,

!

, , , :

#include <iostream>
#include <vector>

using namespace std;

int main() {
        vector<int> to_erase = {0, 1, 2}; 
        vector<int> data     = {3, 3, 3, 3};

        int count_removed = 0;
        for(unsigned int i = 0; i < to_erase.size(); i++)
                data.erase(data.begin() + to_erase[i] - count_removed++);

        for(unsigned int i = 0; i < data.size(); ++i)
                        cout << data[i] << "\n";
        return 0;
}

:

3

I had the same problem when I first used std::erase(), good question, +1.

0
source

I think this is a bad design because you will change the loop invariant and require a lot of workaround for this to happen. Anyway, if you really want to use the for loop, you can specify what you want to remove and run stl remove_if, something like:

#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
using namespace std;

int main() {

    vector<int> to_erase = {0, 1, 2}; 
    vector<int> data     = {3, 3, 3, 3};

    cout << "Before:\n" ;
    for(int i=0; i<data.size(); i++)
        cout << i << "\t";
    cout << endl;   
    for(int i=0; i<data.size(); i++)
        cout << data[i] << "\t";
    cout << endl;

    for(int i = 0; i < to_erase.size(); i++) {
        //data.erase(data.begin() + to_erase[i]);
        data[i] = numeric_limits<int>::max();
    }

    data.erase(remove_if(data.begin(), 
                         data.end(), 
                         [](int i){return i==numeric_limits<int>::max();}), data.end());

    cout << "Next:\n" ;
    for(int i=0; i<data.size(); i++)
        cout << i << "\t";
    cout << endl;
    for(int i=0; i<data.size(); i++)
        cout << data[i] << "\t";

    return 0;
}
0
source

All Articles