I have a source container of strings I want to remove any strings from the source container that match a predicate and add them into the destination container.
remove_copy_if and other algorithms can only reorder the elements in the container, and therefore have to be followed up by the erase member function. My book (Josuttis) says that remove_copy_if returns an iterator after the last position in the destination container. Therefore if I only have an iterator into the destination container, how can I call erase on the source container? I have tried using the size of the destination to determine how far back from the end of the source container to erase from, but had no luck. I have only come up with the following code, but it makes two calls (remove_if and remove_copy_if).
Can someone let me know the correct way to do this? I’m sure that two linear calls is not the way to do this.
#include <iostream> #include <iterator> #include <vector> #include <string> #include <algorithm> #include <functional> using namespace std; class CPred : public unary_function<string, bool> { public: CPred(const string& arString) :mString(arString) { } bool operator()(const string& arString) const { return (arString.find(mString) == std::string::npos); } private: string mString; }; int main() { vector<string> Strings; vector<string> Container; Strings.push_back('123'); Strings.push_back('145'); Strings.push_back('ABC'); Strings.push_back('167'); Strings.push_back('DEF'); cout << 'Original list' << endl; copy(Strings.begin(), Strings.end(),ostream_iterator<string>(cout,'\n')); CPred Pred('1'); remove_copy_if(Strings.begin(), Strings.end(), back_inserter(Container), Pred); Strings.erase(remove_if(Strings.begin(), Strings.end(), not1(Pred)), Strings.end()); cout << 'Elements beginning with 1 removed' << endl; copy(Strings.begin(), Strings.end(),ostream_iterator<string>(cout,'\n')); cout << 'Elements beginning with 1' << endl; copy(Container.begin(), Container.end(),ostream_iterator<string>(cout,'\n')); return 0; }
I see your point, that you’d like to avoid doing two passes over your source container. Unfortunately, I don’t believe there’s a standard algorithm that will do this. It would be possible to create your own algorithm that would copy elements to a new container and remove from the source container (in the same sense as remove_if; you’d have to do an erase afterward) in one pass. Your container size and performance requirements would dictate whether the effort of creating such an algorithm would be better than making two passes.
Edit: I came up with a quick implementation:
Edit: Maybe there is confusion in what is meant by a ‘pass’. In the OP’s solution, there is a call to remove_copy_if() and a call to remove_if(). Each of these will traverse the entirety of the original container. Then there is a call to erase(). This will traverse any elements that were removed from the original container.
If my algorithm is used to copy the removed elements to a new container (using begin() the original container for the output iterator will not work, as dirkgently demonstrated), it will perform one pass, copying the removed elements to the new container by means of a back_inserter or some such mechanism. An erase will still be required, just as with remove_if(). One pass over the original container is eliminated, which I believe is what the OP was after.