c++ STL remove-if algorithm and erase algorithm issue. - c++

Aim : Create a vector. Use remove_if on it
#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>
#include<functional>
using namespace std;
int main()
{
int negative_count=0;
vector<int> v = { 2, -1, -3, 5, -5, 0, 7 };
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
vector<int>::iterator new_it=remove_if(v.begin(), v.end(), bind2nd(greater<int>(), -1));
v.erase(new_it);
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
The output:
The remove_if condition is to remove numbers greater than -1.
Why is it displaying -5 twice?The output after remove_if should be -1 -3 -5 5 0 7 according to me.
Also if i use
V.erase(new_int,v.end())
The output is fine: -1 -3 -5

When you call std::remove/remove_if, it moves elements which don't satisfy the condition to the front of the range. The values of any remaining elements (starting from the position of the returned iterator) are unspecified. Some people seem to think that it swaps the elements such that the ones which satisfy the condition are moved to the back. But the algorithm is not specified to do this. If that's the result you want, then the algorithm you are looking for is std::partition.

The information said replace_if returns a pointer to a new range,So i expected the new range after my output
remove_if returns an iterator.
Namely a one past the end iterator of the range containing only elements that do NOT satisfy the condition. There is no guarantee that the rest of the range will contain all other elements.
std::vector<int> v{ 2, -1, -3, 5, -5, 0, 7 };
auto new_end = std::remove_if(v.begin(), v.end(), [](auto i){ return i > -1; });
// now the range [v.begin(), new_end) contains only elements that are not > -1
// contents of [new_end, v.end()) are unspecified
for(auto i = v.begin(); i!=new_end; ++i)
{
std::cout << *i;
}
erase-remove idiom requires you to specify the whole range of elements to be removed.
Thats because you'd require every item that does match the condition to be removed. not only one.
v.erase(new_end, v.end());

Erase elements Removes from the vector either a single element
(position) or a range of elements ([first,last)).
Above reference is from http://www.cplusplus.com/reference/vector/vector/erase/
This means that in your case, you only erase one element from the vector which is pointed by the iterator returned by remove_if() function. You need to define a ranged as you mentioned at the end:
V.erase(new_int,v.end())

Because remove_if doesn't actually remove anything, it only copies/moves elements satisfying predicate to the end. So you have to write v.erase(new_it, v.end()).
Link

Related

lower_bound() in C++

From reading from the Internet, I understand that The lower_bound() method in C++ is used to return an iterator pointing to the first element in the range [first, last) which has a value not less than value. This means that the function returns the index of the next smallest number just greater than that number.
So, for the given code below I understood that the output is 3. But, as there is repetition of 6. How can I get the index of last 6 using lower_bound(). I can implement my own binary_search() for that, but I want to know how to do it by lower_bound().
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int array[] = {5,6,7,7,6,5,5,6};
vector<int> v(array,array+8); // 5 6 7 7 6 5 5 6
sort (v.begin(), v.end()); // 5 5 5 6 6 6 7 7
vector<int>::iterator lower,upper;
lower = lower_bound (v.begin(), v.end(), 6);
upper = upper_bound (v.begin(), v.end(), 6);
cout << "lower_bound for 6 at position " << (lower- v.begin()) << '\n';
return 0;
}
Use pair of lower_bound and upper_bound. Or one equal_range -- that would be more optimal.
Both upper_bound and high part of equal_range would be past the last "6". The same as end is not last, it is past the last.
You can use reverse iterators into the vector, but then to fulfill the ordering requirement for std::lower_bound you need to inverse the comparison, so you need to use std::greater instead of the default std::less. This however also means that now you are not really looking for a lower bound, but for an upper bound with respect to that comparison function, so:
auto upper = std::upper_bound(v.rbegin(), v.rend(), 6, std::greater{});
If the array is sorted, iterating between lower_bound and upper_bound you get all elements which equal your pivot point:
lower = lower_bound(v.begin(), v.end(), 6);
upper = upper_bound(v.begin(), v.end(), 6);
for (auto it = lower; it != upper; it++) {
assert(6 == *it);
}
The question you are asking, i.e. what is the index of the last 6, doesn't have a corresponding function in the standard library because is ill-defined in the case when the range doesn't contain any 6. In all other cases since you have a random access container you can get an iterator to the last 6 by removing one from upper_bound (upper - 1 in your code), in the same way you get the last index of an array by removing 1 from length.
However I suggest you avoid relying on the position of the last element equal when you design your algorithm. Also note that if you need both lower and upper bound you can get both at the same time with equal_range, which may even perform better because it may be optimised to only traverse the data structure once:
std::tie(lower,upper) = equal_range(v.begin(), v.end(), 6);
for (auto it = lower; it != upper; it++) {
assert(6 == *it);
}
You can use lower_bound again, updating the begin and the value:
auto lower = std::lower_bound (v.cbegin(), v.cend(), 6);
auto upper = std::lower_bound (lower, v.cend(), 6 + 1);
std::cout << "Number of values found: " << std::distance(lower, upper) << '\n';

erase a specific value from a vector array [duplicate]

I'm trying to get a single element from a vector and push it to the back of the vector then remove it so I won't have an empty section in memory. The erase-remove idiom can do this but it removes all instances of a particular value. I just want the first one removed.
I'm not too experienced with standard library algorithms and I can't find the appropriate methods (if any) to do this. Here is an example:
int main() {
std::vector<int> v{1, 2, 3, 3, 4};
remove_first(v, 3);
std::cout << v; // 1, 2, 3, 4
}
So how would I go about removing the first occurance of a 3 from this vector?
Find it first, then erase it:
auto it = std::find(v.begin(),v.end(),3);
// check that there actually is a 3 in our vector
if (it != v.end()) {
v.erase(it);
}
If you don't care about maintaining the ordering of the elements in the vector, you can avoid the copy of the "tail" of remaining elements on erase:
auto it = std::find(v.begin(), v.end(), 3);
if (it != v.end()) {
std::iter_swap(it, v.end() - 1);
v.erase(v.end() - 1);
}

Erase-remove segfaults, but erasing in loop works [duplicate]

Let's say I have std::vector<std::pair<int,Direction>>.
I am trying to use erase-remove_if idiom to remove pairs from the vector.
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));
I want to delete all pairs that have .first value set to 4.
In my example I have pairs:
- 4, Up
- 4, Down
- 2, Up
- 6, Up
However, after I execute erase-remove_if, I am left with:
- 2, Up
- 6, Up
- 6, Up
What am I doing wrong here?
The correct code is:
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool
{ return stopPoint.first == 4; }),
stopPoints.end());
You need to remove the range starting from the iterator returned from std::remove_if to the end of the vector, not only a single element.
"Why?"
std::remove_if swaps elements inside the vector in order to put all elements that do not match the predicate towards the beginning of the container. This means that if the predicate (body of the lambda function) returns true, then that element will be placed at the end of the vector.
remove_if then **returns an iterator which points to the first element which matches the predicate **. In other words, an iterator to the first element to be removed.
std::vector::erase erases the range starting from the returned iterator to the end of the vector, such that all elements that match the predicate are removed.
More information: Erase-remove idiom (Wikipedia).
The method std::vector::erase has two overloads:
iterator erase( const_iterator pos );
iterator erase( const_iterator first, const_iterator last );
The first one only remove the element at pos while the second one remove the range [first, last).
Since you forget the last iterator in your call, the first version is chosen by overload resolution, and you only remove the first pair shifted to the end by std::remove_if. You need to do this:
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool {
return stopPoint.first == 4;
}),
stopPoints.end());
The erase-remove idiom works as follow. Let say you have a vector {2, 4, 3, 6, 4} and you want to remove the 4:
std::vector<int> vec{2, 4, 3, 6, 4};
auto it = std::remove(vec.begin(), vec.end(), 4);
Will transform the vector into {2, 3, 6, A, B} by putting the "removed" values at the end (the values A and B at the end are unspecified (as if the value were moved), which is why you got 6 in your example) and return an iterator to A (the first of the "removed" value).
If you do:
vec.erase(it)
...the first overload of std::vector::erase is chosen and you only remove the value at it, which is the A and get {2, 3, 6, B}.
By adding the second argument:
vec.erase(it, vec.end())
...the second overload is chosen, and you erase value between it and vec.end(), so both A and B are erased.
I know that at the time this question was asked there was no C++20, so just adding answer for completeness & up-to-date answer for this question,
C++20 has now much cleaner & less verbose pattern, using std::erase_if.
See generic code example:
#include <vector>
int main()
{
std::vector<char> cnt(10);
std::iota(cnt.begin(), cnt.end(), '0');
auto erased = std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
std::cout << erased << " even numbers were erased.\n";
}
Specific question code snippet:
std::erase_if(stopPoints, [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; });
see complete details here:
https://en.cppreference.com/w/cpp/container/vector/erase2

Using erase-remove_if idiom

Let's say I have std::vector<std::pair<int,Direction>>.
I am trying to use erase-remove_if idiom to remove pairs from the vector.
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; }));
I want to delete all pairs that have .first value set to 4.
In my example I have pairs:
- 4, Up
- 4, Down
- 2, Up
- 6, Up
However, after I execute erase-remove_if, I am left with:
- 2, Up
- 6, Up
- 6, Up
What am I doing wrong here?
The correct code is:
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool
{ return stopPoint.first == 4; }),
stopPoints.end());
You need to remove the range starting from the iterator returned from std::remove_if to the end of the vector, not only a single element.
"Why?"
std::remove_if swaps elements inside the vector in order to put all elements that do not match the predicate towards the beginning of the container. This means that if the predicate (body of the lambda function) returns true, then that element will be placed at the end of the vector.
remove_if then **returns an iterator which points to the first element which matches the predicate **. In other words, an iterator to the first element to be removed.
std::vector::erase erases the range starting from the returned iterator to the end of the vector, such that all elements that match the predicate are removed.
More information: Erase-remove idiom (Wikipedia).
The method std::vector::erase has two overloads:
iterator erase( const_iterator pos );
iterator erase( const_iterator first, const_iterator last );
The first one only remove the element at pos while the second one remove the range [first, last).
Since you forget the last iterator in your call, the first version is chosen by overload resolution, and you only remove the first pair shifted to the end by std::remove_if. You need to do this:
stopPoints.erase(std::remove_if(stopPoints.begin(),
stopPoints.end(),
[&](const stopPointPair stopPoint)-> bool {
return stopPoint.first == 4;
}),
stopPoints.end());
The erase-remove idiom works as follow. Let say you have a vector {2, 4, 3, 6, 4} and you want to remove the 4:
std::vector<int> vec{2, 4, 3, 6, 4};
auto it = std::remove(vec.begin(), vec.end(), 4);
Will transform the vector into {2, 3, 6, A, B} by putting the "removed" values at the end (the values A and B at the end are unspecified (as if the value were moved), which is why you got 6 in your example) and return an iterator to A (the first of the "removed" value).
If you do:
vec.erase(it)
...the first overload of std::vector::erase is chosen and you only remove the value at it, which is the A and get {2, 3, 6, B}.
By adding the second argument:
vec.erase(it, vec.end())
...the second overload is chosen, and you erase value between it and vec.end(), so both A and B are erased.
I know that at the time this question was asked there was no C++20, so just adding answer for completeness & up-to-date answer for this question,
C++20 has now much cleaner & less verbose pattern, using std::erase_if.
See generic code example:
#include <vector>
int main()
{
std::vector<char> cnt(10);
std::iota(cnt.begin(), cnt.end(), '0');
auto erased = std::erase_if(cnt, [](char x) { return (x - '0') % 2 == 0; });
std::cout << erased << " even numbers were erased.\n";
}
Specific question code snippet:
std::erase_if(stopPoints, [&](const stopPointPair stopPoint)-> bool { return stopPoint.first == 4; });
see complete details here:
https://en.cppreference.com/w/cpp/container/vector/erase2

How do I remove an item from a stl vector with a certain value?

I was looking at the API documentation for stl vector, and noticed there was no method on the vector class that allowed the removal of an element with a certain value. This seems like a common operation, and it seems odd that there's no built in way to do this.
std::remove does not actually erase elements from the container: it moves the elements to be removed to the end of the container, and returns the new end iterator which can be passed to container_type::erase to do the actual removal of the extra elements that are now at the end of the container:
std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());
If you want to remove an item, the following will be a bit more efficient.
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
v.erase(it);
or you may avoid overhead of moving the items if the order does not matter to you:
std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
using std::swap;
// swap the one to be removed with the last element
// and remove the item at the end of the container
// to prevent moving all items after '5' by one
swap(*it, v.back());
v.pop_back();
}
Use the global method std::remove with the begin and end iterator, and then use std::vector.erase to actually remove the elements.
Documentation links
std::remove http://www.cppreference.com/cppalgorithm/remove.html
std::vector.erase http://www.cppreference.com/cppvector/erase.html
std::vector<int> v;
v.push_back(1);
v.push_back(2);
//Vector should contain the elements 1, 2
//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);
//Erase the "removed" elements.
v.erase(newEnd, v.end());
//Vector should now only contain 2
Thanks to Jim Buck for pointing out my error.
From c++20:
A non-member function introduced std::erase, which takes the vector and value to be removed as inputs.
ex:
std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);
The other answers cover how to do this well, but I thought I'd also point out that it's not really odd that this isn't in the vector API: it's inefficient, linear search through the vector for the value, followed by a bunch of copying to remove it.
If you're doing this operation intensively, it can be worth considering std::set instead for this reason.
If you have an unsorted vector, then you can simply swap with the last vector element then resize().
With an ordered container, you'll be best off with ‍std::vector::erase(). Note that there is a std::remove() defined in <algorithm>, but that doesn't actually do the erasing. (Read the documentation carefully).
*
C++ community has heard your request :)
*
C++ 20 provides an easy way of doing it now.
It gets as simple as :
#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);
You should check out std::erase and std::erase_if.
Not only will it remove all elements of the value (here '0'), it will do it in O(n) time complexity. Which is the very best you can get.
If your compiler does not support C++ 20, you should use erase-remove idiom:
#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());
See also std::remove_if to be able to use a predicate...
Here's the example from the link above:
vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 4 2 8 5 7"
vector<int>::iterator new_end =
remove_if(V.begin(), V.end(),
compose1(bind2nd(equal_to<int>(), 0),
bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]
copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 5 7".
A shorter solution (which doesn't force you to repeat the vector name 4 times) would be to use Boost:
#include <boost/range/algorithm_ext/erase.hpp>
// ...
boost::remove_erase(vec, int_to_remove);
See http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html
Two ways are there by which you can use to erase an item particularly.
lets take a vector
std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);
1) Non efficient way : Although it seems to be quite efficient but it's not because erase function delets the elements and shifts all the elements towards left by 1.
so its complexity will be O(n^2)
std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
if(*itr == value)
{
v.erase(itr);
}
else
++itr;
}
2) Efficient way ( RECOMMENDED ) : It is also known as ERASE - REMOVE idioms .
std::remove transforms the given range into a range with all the elements that compare not equal to given element shifted to the start of the container.
So, actually don't remove the matched elements.
It just shifted the non matched to starting and gives an iterator to new valid end.
It just requires O(n) complexity.
output of the remove algorithm is :
10 20 30 50 40 50
as return type of remove is iterator to the new end of that range.
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
Now use vector’s erase function to delete elements from the new end to old end of the vector. It requires O(1) time.
v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );
so this method work in O(n)
Similar to the erase remove idiom, for vector one could use resize and remove and use iterator distance computation:
std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.resize(std::remove(vec.begin(), vec.end(), int_to_remove) - vec.begin());
Tested here.
If you want to do it without any extra includes:
vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
IComponent* juggler;
if (componentToRemove != NULL)
{
for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
{
if (componentToRemove == myComponents[currComponentIndex])
{
//Since we don't care about order, swap with the last element, then delete it.
juggler = myComponents[currComponentIndex];
myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
myComponents[myComponents.size() - 1] = juggler;
//Remove it from memory and let the vector know too.
myComponents.pop_back();
delete juggler;
}
}
}
}