Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Removing elements

Because of the genericity of the STL, the concept of removal is a bit constrained. Since elements can only be removed via iterators, and iterators can point to arrays, vectors, lists, and so on, it is not safe or reasonable to try to destroy the elements that are being removed and to change the size of the input range [first, last). (An array, for example, cannot have its size changed.) So instead, what the STL remove functions do is rearrange the sequence so that the removed elements are at the end of the sequence, and the un-removed elements are at the beginning of the sequence (in the same order that they were before, minus the removed elements that is, this is a stable operation). Then the function will return an iterator to the new last element of the sequence, which is the end of the sequence without the removed elements and the beginning of the sequence of the removed elements. In other words, if new_last is the iterator that is returned from the remove function, [first, new_last) is the sequence without any of the removed elements, and [new_last, last) is the sequence of removed elements.

If you are simply using your sequence, including the removed elements, with more STL algorithms, you can just use new_last as the new past-the-end iterator. However, if you re using a resizable container c (not an array) and you want to eliminate the removed elements from the container, you can use erase( ) to do so, for example:

c.erase(remove(c.begin(), c.end(), value), c.end());
 

You can also use the resize( ) member function that belongs to all standard sequences (more on this in the next chapter).

The return value of remove( ) is the new_last iterator, so erase( ) deletes all the removed elements from c.

The iterators in [new_last, last) are dereferenceable, but the element values are unspecified and should not be used.

ForwardIterator remove(ForwardIterator first,
ForwardIterator last, const T& value);
ForwardIterator remove_if(ForwardIterator first,
ForwardIterator last, Predicate pred);
OutputIterator remove_copy(InputIterator first,
InputIterator last, OutputIterator result, const T&
value);
OutputIterator remove_copy_if(InputIterator first,
InputIterator last, OutputIterator result, Predicate
pred);

Each of the remove forms moves through the range [first, last), finding values that match a removal criterion and copying the unremoved elements over the removed elements (thus effectively removing them). The original order of the unremoved elements is maintained. The return value is an iterator pointing past the end of the range that contains none of the removed elements. The values that this iterator points to are unspecified.

The if versions pass each element to pred( ) to determine whether it should be removed. (If pred( ) returns true, the element is removed.) The copy versions do not modify the original sequence, but instead copy the unremoved values into a range beginning at result and return an iterator indicating the past-the-end value of this new range.

ForwardIterator unique(ForwardIterator first,
ForwardIterator last);
ForwardIterator unique(ForwardIterator first,
ForwardIterator last, BinaryPredicate binary_pred);
OutputIterator unique_copy(InputIterator first,
InputIterator last, OutputIterator result);
OutputIterator unique_copy(InputIterator first,
InputIterator last, OutputIterator result,
BinaryPredicate binary_pred);

Each of the unique functions moves through the range [first, last), finding adjacent values that are equivalent (that is, duplicates) and removing the duplicate elements by copying over them. The original order of the unremoved elements is maintained. The return value is an iterator pointing past the end of the range that has the adjacent duplicates removed.

Because only duplicates that are adjacent are removed, it s likely that you ll want to call sort( ) before calling a unique algorithm, since that will guarantee that all the duplicates are removed.

For each iterator value i in the input range, the versions containing binary_pred call:

binary_pred(*i, *(i-1));
 

and if the result is true, *i is considered a duplicate.

The copy versions do not modify the original sequence, but instead copy the unremoved values into a range beginning at result and return an iterator indicating the past-the-end value of this new range.

Example

This example gives a visual demonstration of the way the remove and unique functions work.

//: C06:Removing.cpp
// The removing algorithms.
//{L} Generators
#include <algorithm>
#include <cctype>
#include <string>
#include "Generators.h"
#include "PrintSequence.h"
using namespace std;
 
struct IsUpper {
bool operator()(char c) { return isupper(c); }
};
 
int main() {
string v;
v.resize(25);
generate(v.begin(), v.end(), CharGen());
print(v.begin(), v.end(), "v original", "");
// Create a set of the characters in v:
string us(v.begin(), v.end());
sort(us.begin(), us.end());
string::iterator it = us.begin(), cit = v.end(),
uend = unique(us.begin(), us.end());
// Step through and remove everything:
while(it != uend) {
cit = remove(v.begin(), cit, *it);
print(v.begin(), v.end(), "Complete v", "");
print(v.begin(), cit, "Pseudo v ", " ");
cout << "Removed element:\t" << *it
<< "\nPsuedo Last Element:\t"
<< *cit << endl << endl;
++it;
}
generate(v.begin(), v.end(), CharGen());
print(v.begin(), v.end(), "v", "");
cit = remove_if(v.begin(), v.end(), IsUpper());
print(v.begin(), cit, "v after remove_if IsUpper", " ");
// Copying versions are not shown for remove()
// and remove_if().
sort(v.begin(), cit);
print(v.begin(), cit, "sorted", " ");
string v2;
v2.resize(cit - v.begin());
unique_copy(v.begin(), cit, v2.begin());
print(v2.begin(), v2.end(), "unique_copy", " ");
// Same behavior:
cit = unique(v.begin(), cit, equal_to<char>());
print(v.begin(), cit, "unique equal_to<char>", " ");
} ///:~
 

The string v is a container of characters filled with randomly generated characters. Each character is used in a remove statement, but the entire string v is displayed each time so you can see what happens to the rest of the range, after the resulting endpoint (which is stored in cit).

To demonstrate remove_if( ), the standard C library function isupper( ) (in <cctype>) is called inside the function object class IsUpper, an object of which is passed as the predicate for remove_if( ). This returns true only if a character is uppercase, so only lowercase characters will remain. Here, the end of the range is used in the call to print( ) so only the remaining elements will appear. The copying versions of remove( ) and remove_if( ) are not shown because they are a simple variation on the noncopying versions, which you should be able to use without an example.

The range of lowercase letters is sorted in preparation for testing the unique functions. (The unique functions are not undefined if the range isn t sorted, but it s probably not what you want.) First, unique_copy( ) puts the unique elements into a new vector using the default element comparison, and then uses the form of unique( ) that takes a predicate. The predicate is the built-in function object equal_to( ), which produces the same results as the default element comparison.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire