Vector Erase Confusion

Hi everyone,

I'm trying to convert some C++ code to another language but I'm struggling to understand what a couple lines of code are doing. Here are the two codes:
1
2
3
4
5
6
vector<double> values; //Definition
  values.erase(std::remove_if(values.begin(), values.end(), [&](const double& x) { return x < chart_options.start || x > chart_options.end; }), values.end());

  vector<double> values; //Definition
  rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());


My understanding is that vector.erase erases any value from vector.start to vector.end - vector.erase(startpoint,endpoint)

But in the startpoint bit of the first code we have an if statement that seems to be doing the same thing? it removes values x from the vector if they satisfy the conditions, but then that somehow becomes the start point of the erase?

As for the second one, the beginning point is a vector? You remove non-unique contiguous values and then make that the startpoint?
See this:

https://cplusplus.com/reference/algorithm/remove_if/?kw=remove_if
https://cplusplus.com/reference/algorithm/unique/

Both remove_if() and unique() are moving the determined elements towards the end of the container. Note that those element moved to the end will be destructed i.e. they are not usable anymore. The result of both functions is the iterator of the first removed value (end() if none).
The erase() function takes two iterators to determine which element needs to be erased from the container. The first iterator is provided by those functions and the second is the end() iterator.
Note that both functions may return end() which is not a problem because erase(...) can handle that.
Erase_if is a little bit more elaborated than a single research about a value inside a vector. It returns true if a compare is validated. So in this case, you can elaborate function inside your operation erase ++

https://en.cppreference.com/w/cpp/container/vector/erase2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    // erase all even numbers
    std::erase_if(v, [](char x) { return (x - '0') % 2 == 0; });

    for(int i : v) 
	std::cout << i << std::endl;

    return 0;
}
Last edited on
# Simulate erase-remove_if (produces new object)
values = [ 3, -2, 13, 7, 42, 6, 3 ]
values = [ x for x in values if x >= 1 and x <= 10 ]
print( values )

# Simulate erase-unique (produces new, differently-named, object)
values = [ 10, 20, 20, 20, 30, 30, 20, 20, 10 ]
filtered = [ values[0] ]
for x in values:
    if x != filtered[-1]: filtered.append( x )
print( filtered )


[3, 7, 6, 3]
[10, 20, 30, 20, 10]

The remove-erase idiom. Is part of confusion from the use of both remove and erase in same statement?

You could write:
1
2
3
4
5
6
7
8
9
10
11
auto newend = std::remove_if(values.begin(), values.end(),
              [&](const double& x)
              { return x < chart_options.start || x > chart_options.end; });
// newend is an iterator
values.erase( newend, values.end() );

const auto N = rtnend.size();
auto rtnend = std::unique(rtn.begin(), rtn.end()); // rtnend is an iterator
assert( rtnend.size() == N );
rtn.erase( rtnend, rtn.end() );
assert( rtnend.size() <= N );

Now it is perhaps more clear that erase() changes the size, while the remove_if() and unique() only modify elements.

Yes, calling algorithm that does not remove elements "remove" can be very confusing.
If it's of the format .erasexxx() then it's a member function and will actually remove the element(s) from the container and adjust its size. If it's of the format std::removexxx() then it will move/shuffle all elements to be removed to the end of the container and return an iterator pointing to one past the last element not moved. The actual size of the container isn't changed. Having a new 'end' pointer is often all you need so that instead of using .end() etc you use this returned iterator instead. If you really need to erase those elements, then you use .erase() with the beginning point the returned iterator and the end point .end().

"remove doesn't remove but erase deletes"

[based upon the 'famous' chemistry quote - Boyle didn't boil but Charlie cooked - relating to pressure/temperature/volume]
Last edited on
If you didn't want to modify the original, there's std::unique_copy.
Topic archived. No new replies allowed.