338
vector<int> myVector;

and lets say the values in the vector are this (in this order):

5 9 2 8 0 7

If I wanted to erase the element that contains the value of "8", I think I would do this:

myVector.erase(myVector.begin()+4);

Because that would erase the 4th element. But is there any way to erase an element based off of the value "8"? Like:

myVector.eraseElementWhoseValueIs(8);

Or do I simply just need to iterate through all the vector elements and test their values?

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Jake Wilson
  • 88,616
  • 93
  • 252
  • 370
  • 6
    @BenVoigt: your question is quite arrogant - clearly the guy cannot answer it, what YOU should have done is create an answer that covers all the cases you mention. – slashmais Nov 18 '16 at 04:45
  • 7
    @slashmais: Oh nonsense, my clarifying question was quite simple and doesn't require an expert programmer to answer. And there's no way I could cover all possible values of "what do you want to do?" for all three of the cases. Just for the case of "no matching elements" possible behaviors include "nothing", "throw an exception", "return an error", "exit the process (possibly via `assert()`)", "log a message to `std::cerr`"... and even those aren't exhaustive. No, the asker of the question needs to state the error handling policy, and whether finding no matches even is an error. – Ben Voigt Nov 18 '16 at 06:39
  • 3
    ... case of QED. i think – slashmais Nov 18 '16 at 08:49

4 Answers4

557

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.

Community
  • 1
  • 1
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • 2
    I'm a bit confused... It appears this would erase elements from the vector from the element that I'm looking to erase, all the way to the end of the vector... Am I incorrect? All I want is that one element removed. – Jake Wilson Aug 02 '10 at 06:09
  • 13
    @jak: Take a look at the description of `remove()`: It moves all values not equal to the value passed to the beginning of the range `[begin,end)`. With your example in the question you'd get `5,9,2,0,7,7`. As `remove()` however returns an iterator to the new end, `vec.erase()` can remove the obsolete elements (i.e. the second `7` here) if that is needed. – Georg Fritzsche Aug 02 '10 at 06:28
  • 1
    Is it still necessary to call resize if erase() is used? (If so might consider including it in the answer?) – Assimilater Apr 05 '15 at 04:42
  • 3
    @Assimilater: It is not necessary. – Georg Fritzsche Apr 07 '15 at 12:45
  • 2
    what is the complexity of this procedure? O(n) ??? – shane Jun 23 '16 at 08:24
  • 2
    @shane The complexities of `erase()` and `remove()` are documented, see e.g. on [cppreference](http://en.cppreference.com/w/). – Georg Fritzsche Jun 23 '16 at 11:03
  • 17
    @GeorgFritzsche Why can't you just answer his question instead of sending him a link? Yes, it is O(n) –  Dec 09 '17 at 13:22
  • 4
    @AlisherKassymov Because the answer is easily found there. And it's a better approach for learning. Different people have different approaches, something worth respecting. – Georg Fritzsche Jan 04 '18 at 08:16
  • 5
    The dumb part of this algorithm is that remove doesn't stop when it finds the first match. It is inefficient to keep comparing the rest of the list. So this is great if there are potentially multiple copies of the same value in the vector, but it isn't a good answer for the common scenario of a vector of unique values. In that case, the std::find is a better option. – srm Jan 14 '20 at 19:22
  • Wouldn't it be great if there were `"erase_first"` and `"erase_all"` functions on vector? I know vector isn't intended for frequent removals - `list`, `deque` or possibly `set` should be used - but vector is memory efficient so a sensible choice in many situations even when there is some erasing. – Richard Whitehead Mar 06 '20 at 14:20
  • I was in doubt about what would happen if `remove` wouldn't find any element, we would end up with `vec.erase(vec.end(),vec.end()`. Then looking at the documentation of `erase`, which says elements in the interval `[a,b)` are deleted, I thought that the element pointed by the first argument would be definitely deleted, being `[` inclusive. What I had not considered is that the interval `[a,a)` is empty, despite the `[` – Antonio Jun 17 '22 at 15:05
145

You can use std::find to get an iterator to a value:

#include <algorithm>
std::vector<int>::iterator position = std::find(myVector.begin(), myVector.end(), 8);
if (position != myVector.end()) // == myVector.end() means the element was not found
    myVector.erase(position);
Community
  • 1
  • 1
zneak
  • 134,922
  • 42
  • 253
  • 328
  • 19
    This is good if you only expect one occurence of that value. – Tomáš Zato Nov 16 '15 at 08:46
  • 17
    @TomášZato: Or want only one removed, which seems to be the case for this question. – Gauthier Jun 02 '16 at 11:32
  • 3
    For removing all the values, initialize `position = myVector.begin()` and enclose everything in a `while(position != myVector.end())` loop – subtleseeker Jun 17 '18 at 16:17
  • `Error C2676 binary '==': 'action' does not define this operator or a conversion to a type acceptable to the predefined operator` in `xutility`. Literally any method I come across for this example gives me this error. – IOviSpot Oct 08 '20 at 18:05
  • Voted down because this is really not the way you should do this (the most upvoted answer is the correct way). – Carlo Wood Sep 13 '21 at 12:13
  • @CarloWood it's the correct way if you want to remove a single element. – Stefan Riedel Jul 26 '23 at 11:16
  • @StefanRiedel I don't think that is related. The downside of this method is that if position is not near the end of the vector, then a lot of elements need to be moved. On the "upside", this method keeps all elements in the vector in the same order, but I'd argue that in that case you probably shouldn't be using a vector in the first place. For example if we start with {1, 2, 3, 4, 5, 6, 7} and find and erase 3; this method moves 4, 5, 6 and 7 one place back to get {1, 2, 4, 5, 6, 7}. The accepted answer method instead, swaps the 3 with the 7 and then erases the last element (which is fast!). – Carlo Wood Jul 26 '23 at 14:30
  • The result in that case would thus be {1, 2, 7, 4, 5, 6} and nothing had to be moved. PS in the previous comment "in that case" should be "if you need that". – Carlo Wood Jul 26 '23 at 14:31
  • @CarloWood it all depends on the actual needs. OP uses a vector so I assume he needs fast iteration and probably fixed order. I'm not questioning his choice of container, because I can't know what he needs. And based on that, the correct way of deleting a single element is `find` -> `erase`. If fixed order is not needed (and again, we don't know) `find` -> `swap` -> `erase` may be better. But in case OP wants to delete all elements meeting that criteria, the accepted answer is the way to go. – Stefan Riedel Jul 28 '23 at 15:11
  • @CarloWood And no, `std::remove` (and therefor the accepted answer) preserves the order of elements that are not to be removed, so it doesn't swap 3 with 7. Source: https://en.cppreference.com/w/cpp/algorithm/remove – Stefan Riedel Jul 28 '23 at 15:13
15

You can not do that directly. You need to use std::remove algorithm to move the element to be erased to the end of the vector and then use erase function. Something like: myVector.erase(std::remove(myVector.begin(), myVector.end(), 8), myVec.end());. See this erasing elements from vector for more details.

Community
  • 1
  • 1
Naveen
  • 74,600
  • 47
  • 176
  • 233
2

Eric Niebler is working on a range-proposal and some of the examples show how to remove certain elements. Removing 8. Does create a new vector.

#include <iostream>
#include <range/v3/all.hpp>

int main(int argc, char const *argv[])
{
    std::vector<int> vi{2,4,6,8,10};
    for (auto& i : vi) {
        std::cout << i << std::endl;
    }
    std::cout << "-----" << std::endl;
    std::vector<int> vim = vi | ranges::view::remove_if([](int i){return i == 8;});
    for (auto& i : vim) {
        std::cout << i << std::endl;
    }
    return 0;
}

outputs

2
4
6
8
10
-----
2
4
6
10

kometen
  • 6,536
  • 6
  • 41
  • 51