std::vector<int> Array;
std::vector<int>::iterator Iter;
Iter = Array.begin() + 2;
Array.erase(Iter);
Is there a faster and better way to go about doing it? Or am I doing it wrongly?
Thanks.
Removing an item from STL::Vector
What is the fastest way to remove an element from the stl::vector while keeping the order of the arrangement?
For example to erase the 3rd element, 'Array[2]', I use:
Quote:Original post by littlekidstd::vector<int> Array;std::vector<int>::iterator Iter;Iter = Array.begin() + 2;Array.erase(Iter);
I don't see any particular reason to keep that temporary iterator around, unless you're going to be using it again. For this simple case, you could just say
Array.erase(Array.begin( ) + 2);
You can find more basic information on std::vectors here.Moral of the story: there's nothing wrong with what you're doing, but you could simplify it for trivial cases. [smile]
-jouley
Jouley says it how it is.. ;)
Also, Here! has helped me throughout my vector endeavors... that sorta rhymes?
Also, Here! has helped me throughout my vector endeavors... that sorta rhymes?
0) Like jouley said.
1) If you want to remove 'Array[2]', you'd better be sure the vector is at least that long first. :)
2) If you will remove several things at a time, you should instead try to make use of the standard library algorithms std::remove or std::remove_if. Each of these operates over a range, shuffling everything that *shouldn't* be removed to the beginning of the range, and leaving the contents of the rest of the range *undefined*. It will return an iterator pointing just past the end of the "unremoved" elements, which allows you to clean up by using the *free function* std::erase, which is another standard library algorithm that removes a range of elements from a container.
Put together, their use is called the "erase-remove idiom", and it looks like this:
1) If you want to remove 'Array[2]', you'd better be sure the vector is at least that long first. :)
2) If you will remove several things at a time, you should instead try to make use of the standard library algorithms std::remove or std::remove_if. Each of these operates over a range, shuffling everything that *shouldn't* be removed to the beginning of the range, and leaving the contents of the rest of the range *undefined*. It will return an iterator pointing just past the end of the "unremoved" elements, which allows you to clean up by using the *free function* std::erase, which is another standard library algorithm that removes a range of elements from a container.
Put together, their use is called the "erase-remove idiom", and it looks like this:
std::vector<std::string> > serious_words;// Our boss just informed us that "warthog" is a silly word, so we// have to remove every occurrance of "warthog" from serious_words.// We do it like this:std::erase(std::remove(serious_words.begin(), serious_words.end(), "warthog"), serious_words.end());// The remove() call gives an iterator one past the end of the remaining// serious words, which is therefore the beginning of the range we must erase.// Later, we have to remove all the words that have a 'q' in them.// First, we need a binary function - or "predicate" - that will tell us// whether a given string contains a q:bool has_q(const std::string& s) { return s.find('q') != std::string::npos;}// Then we can use the remove_if form:std::erase(std::remove_if(serious_words.begin(), serious_words.end(), has_q), serious_words.end());// This can also be made to work with functors, or with specially "adapted"// member functions using something like std::mem_fun_ref.
Quote:Original post by ZahlmanFixed. [smile]
0) Like jouley said.
1) If you want to remove 'Array[2]', you'd better be sure the vector is at least that long first. :)
2) If you will remove several things at a time, you should instead try to make use of the standard library algorithms std::remove or std::remove_if. Each of these operates over a range, shuffling everything that *shouldn't* be removed to the beginning of the range, and leaving the contents of the rest of the range *undefined*. It will return an iterator pointing just past the end of the "unremoved" elements, which allows you to clean up by using the *member function* std::erase, which removes a range of elements from the container.
Put together, their use is called the "erase-remove idiom", and it looks like this:std::vector<std::string> serious_words;// Our boss just informed us that "warthog" is a silly word, so we// have to remove every occurrance of "warthog" from serious_words.// We do it like this:serious_words.erase(std::remove(serious_words.begin(), serious_words.end(), "warthog"), serious_words.end());// The remove() call gives an iterator one past the end of the remaining// serious words, which is therefore the beginning of the range we must erase.// Later, we have to remove all the words that have a 'q' in them.// First, we need a binary function - or "predicate" - that will tell us// whether a given string contains a q:bool has_q(const std::string& s) { return s.find('q') != std::string::npos;}// Then we can use the remove_if form:serious_words.erase(std::remove_if(serious_words.begin(), serious_words.end(), has_q), serious_words.end());// This can also be made to work with functors, or with specially "adapted"// member functions using something like std::mem_fun_ref.
Σnigma
Another thing to be aware of is that since std::vector stores its contents in contiguous memory, removing elements from anywhere except the end of a vector can be an expensive operation. If you need to do so often or you are storing elements that are expensive to copy you might be better off using a different container like a std::list (or possibly a std::deque).
Though as always, make the decision based on your needs and what profiling the code tells you.
Though as always, make the decision based on your needs and what profiling the code tells you.
Quote:Original post by EnigmaQuote:Original post by ZahlmanFixed. [smile]
0) Like jouley said.
1) If you want to remove 'Array[2]', you'd better be sure the vector is at least that long first. :)
2) If you will remove several things at a time, you should instead try to make use of the standard library algorithms std::remove or std::remove_if. Each of these operates over a range, shuffling everything that *shouldn't* be removed to the beginning of the range, and leaving the contents of the rest of the range *undefined*. It will return an iterator pointing just past the end of the "unremoved" elements, which allows you to clean up by using the *member function* std::erase, which removes a range of elements from the container.
Put together, their use is called the "erase-remove idiom", and it looks like this:std::vector<std::string> serious_words;// Our boss just informed us that "warthog" is a silly word, so we// have to remove every occurrance of "warthog" from serious_words.// We do it like this:serious_words.erase(std::remove(serious_words.begin(), serious_words.end(), "warthog"), serious_words.end());// The remove() call gives an iterator one past the end of the remaining// serious words, which is therefore the beginning of the range we must erase.// Later, we have to remove all the words that have a 'q' in them.// First, we need a binary function - or "predicate" - that will tell us// whether a given string contains a q:bool has_q(const std::string& s) { return s.find('q') != std::string::npos;}// Then we can use the remove_if form:serious_words.erase(std::remove_if(serious_words.begin(), serious_words.end(), has_q), serious_words.end());// This can also be made to work with functors, or with specially "adapted"// member functions using something like std::mem_fun_ref.
Σnigma
Blaaaargh. You are correct, of course. I knew something was up... I was going to write on explaining about why remove(_if) can't affect the container size, and then deleted that when I saw that my 'erase' was affecting the container size... missing the obvious aren't I :(
This is one reason why I recommend wrapping the idiom in a function :)
// cause the container to not contain anything matching p.template <typename Container, typename Predicate>inline void filter_out(Container& c, Predicate p) { c.erase(std::remove_if(c.begin(), c.end(), p), c.end());}// cause the container to *only* contain things matching p.// Raw function pointers won't work as predicates any more; adapt them// using std::ptr_fun first.template <typename Container, typename AdaptablePredicate>inline void filter(Container& c, AdaptablePredicate p) { c.erase(std::remove_if(c.begin(), c.end(), std::not1(p)), c.end());}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement