How to Erase an Element from Std::Vector≪≫ by Index

How do I erase an element from std::vector by index?

To delete a single element, you could do:

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));

Or, to delete more than one element at once:

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));

Erasing indices of std::vector inside a for loop based on vector size

Each time you erase() an element from a container, its size() decrements, and the indexes of the remaining elements are decremented as well. But you are incrementing your loop counter unconditionally, so every time you erase an element, you skip the next element that had followed it!

Also, you are passing your vector by-value, so you are operating on a copy of the vector, and the caller will not see any changes in the original vector.

The correct approach would be to either:

  1. increment your index variable inside of the loop body only when an element is NOT erased. Leave the variable as-is when you DO erase an element:

    void FilterContours( std::vector<std::vector<cv::Point>> &contours )
    {
    int i = 0;
    while ( i < contours.size() ) {
    if ( contours[i].size() < 5 ) {
    contours.erase(contours.begin() + i);
    continue;
    }

    //Other filtering...

    ++i;
    }
    }
  2. use iterators instead of indexes:

    void FilterContours( std::vector<std::vector<cv::Point>> &contours )
    {
    auto it = contours.begin();
    while ( it != contours.end() ) {
    if ( it->size() < 5 ) {
    it = contours.erase(it);
    continue;
    }

    //Other filtering...

    ++it;
    }
    }
  3. use the erase-remove idiom:

    void FilterContours( std::vector<std::vector<cv::Point>> &contours )
    {
    contours.erase(
    std:::remove_if(
    contours.begin(),
    contours.end(),
    [](const std::vector<cv::Point> &v)
    {
    if (v.size() < 5) return true;
    //Other filtering...
    return false;
    }
    ),
    contours.end()
    );
    }

How to erase multiple elements from std::vector by index using erase function?

Reverse the order you remove values, i.e. use the reverse iterators of removelist. This of course relies on removelist being sorted.

Perhaps something like

std::sort(removelist.begin(), removelist.end());  // Make sure the container is sorted
for (auto &i = removelist.rbegin(); i != removelist.rend(); ++ i)
{
a.erase(a.begin() + *i);
}

Remove ith item from a C++ std::vector

pList.erase(pList.begin()+i);

To remove element with index i.

C++ Erase vector element by value rather than by position?

How about std::remove() instead:

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 8), vec.end());

This combination is also known as the erase-remove idiom.

Delete from specific indexes in a std::vector

You could use the erase function. For this specific case you mention something like this:

myvector.erase (myvector.begin()+3);
myvector.erase (myvector.begin()+1);

will do the trick. You have to provide an iterator to the erase function and I suggest you read documentation for its use. The above should work for your case. Note that each call to erase will change the index of the remaining elements AFTER the removed position though as the internal array elements will be adjusted relative to the item removed.

In response to your comment, you can only erase one element at a time, UNLESS they are contiguous indices in which case you can use the range based version of erase taking a start and end iterator.
For example if you want to erase indices 1,2 AND 3 use

myvector.erase (myvector.begin()+1,myvector.begin()+4);

As I already mentioned the indices of items after the one you erase will downshift accordingly. This is unavoidable though as an array cannot have "gaps" in it.

How to change the index of a vector element?

When you do insert + remove (or the double splice in JavaScript) you move all of the items between the larger of the two indices and the end of the array twice: first you move them back one slot for the remove, and then you move them forward one slot for the insert. But this is unnecessary. Instead you can simply take a slice of the Vec and rotate it:

fn move_me(arr: &mut [String], old_index: usize, new_index: usize) {
if old_index < new_index {
arr[old_index..=new_index].rotate_left(1);
} else {
arr[new_index..=old_index].rotate_right(1);
}
}

Note that this change allows move_me to take &mut [String] instead of &mut Vec<String>, which makes this code more general as well as more efficient. It is better to accept &[T] instead of &Vec<T>, and in this case the same logic applies to &mut Vec<T> because move_me does not need to grow or shrink the vector.

Also, as in the other answer, I have left out the part that makes negative indices count from the back of the slice, and the part that grows the vector when the index is too large, because neither of those conventions is common in idiomatic Rust.

How to change a particular element of a C++ STL vector

at and operator[] both return a reference to the indexed element, so you can simply use:

l.at(4) = -1;

or

l[4] = -1;


Related Topics



Leave a reply



Submit