Careful selection of methods to delete elements

Source: Internet
Author: User

To summarize this article, there are a total of the following points to keep in mind:

1. To delete all objects with a specific value in the container:

(1) If the container is a vector, string, or deque, use the Erase-remove idiom.

(2), if the container is a list, use the List::remove

(3) If the container is a standard associative container, its erase member function is used.


eg: Suppose you have a labeled STL container C, which contains integers of type int: container<int> C;

And you want to delete all elements in C that have a value of 1963. You can use Erase-remove and idioms:

C.erase (Remove (C.begin (), C.end (), 1963), C.end ()); //When C is VECOTR, string, or deque,

Erase-remove customary usage is the best way to remove elements of a particular value

For list, the same approach applies, according to effective STL, the list member function remove is more efficient:

C.remove (1963); //When C is list, the Remove member function

Is the best way to delete elements of a specific value

For associative containers, the correct way to solve the problem is to call erase:

C.erase (1963); //When C is a standard associative container,

The Erase member function is the best way to remove a particular value element.


2. To delete all objects in the container that satisfy a particular discriminant (condition):

(1) If the container is a vector, string, or deque, use the Erase-remove-if idiom.

(2), if the container is list, use list::remove_if.

(3), if the container is a standard associative container, use remove_copy_if and swap, or write a loop to traverse the elements in the container, and remember to increment the iterator when it is passed to erase.

(4), to do something inside the loop (except for the deletion of objects) operation:

If the container is a standard sequence container, write a loop to traverse the elements in the container, Remember to update the iterator with its return value each time you call erase.

If the container is a standard associative container, write a loop to traverse the elements in the container, remembering that when the iterator is passed to erase, the iterator is incremented.


Eg: Continue with the above container, now let's give the question a little bit. Instead of removing all elements that are equal to a particular value from C, we remove each object that causes the following discriminant (predicate) to return true:


BOOL Badvalue (int x); Returns whether X is a "bad value"

For the sequence container (Vector,string,deque and list), we replace each call to remove with a call to remove_if:

C.erase (Remove_if (C.begin (), C.end (), Badvalue), C.end ()); When C is a vector, string, or deque,

This is the best way to remove objects that make Badvalue return true.

C.remove_if (Badvalue); When C is a list, this is the best way to remove the object that makes Badvalue return true.


Assoccontainer<int> C; C is now a standard associative container

...

Assoccontainer<int> goodvalues; Temporary container for saving values that are not deleted

Remove_copy_if (C.begin (), C.end (),//copy non-deleted values from C to goodvalues

Inserter (Goodvalues,

Goodvalues.end ()),

Badvalue);

C.swap (goodvalues); Exchange the contents of C and Goodvalues

The disadvantage of this approach is the need to replicate all elements that are not deleted, and we may not want to pay so much for the replication cost.


We can also remove elements directly from the original container, thus reducing the cost. However, because the associative container does not provide a member function like remove_if, we must write a loop to traverse the elements in C and delete the elements in the traversal.

Conceptually, the task is simple. In fact, the code is simple. Unfortunately, the code that comes to mind at once rarely happens to be code that works. For example, the next side is a lot of code that we can think of first:

Assoccontainer<int> C;

...

for (Assoccontainer<int>::iterator i = C.begin (); I! = C.end (); ++i)

{

if (Badvalue (*i)) c.erase (i);

}

Unfortunately, this can lead to indeterminate behavior. When an element in a container is deleted, all iterators that point to that element become invalid. Once C.erase (i) returns , I becomes an invalid value. For this loop, it's a bad news. Because the ++i portion of the For loop is incremented after erase returns.


To avoid this problem, we want to make sure that there is an iterator pointing to an element in C before calling erase.

The simplest way to do this is. When called, the suffix increment is used for I:

Assoccontainer<int> C;

...

for (Assoccontainer<int>::iterator i = C.begin ();

I! = C.end (); The third part of the//for loop is empty, and I increments below.

/ * Do not do anything * * )

{

if (Badvalue (*i)) c.erase (i++); //For bad value, transfer current I to erase, increment i is side effect

else ++i; //Pair good value, then simply increment

}


Let's change the question a bit further. Now, not only do we want to remove the element that makes Badvalue return true, we also want to write a message to a log file each time the element is deleted.

For associative containers, this is very simple, because it requires not only a simple modification of the loop just now:

<span style= "FONT-SIZE:18PX;" >ofstream LogFile;                               Log file to write <span style= "White-space:pre" ></span>AssocContainer<int> c;...for (assoccontainer< Int>::iterator i = C.begin (); I! = C.end (); The third part of the For loop is empty, and I increments below. /* Do nothing * *) {if (Badvalue (*i)) {<span style= "white-space:pre" ></span>logfile << "erasing" << *i << ' \ n '; Write log file c.erase (i++);//For bad value, put current I to erase, increment i is side effect}else ++i; For good values, the}</span> is simply incremented

for vectors, strings, and deque, we have to take different strategies, especially to take advantage of the return value of erase. The return value is exactly what we need: Once erase is complete, it is a valid iterator that points to the next element immediately following the deleted element. Or, we can write this:

<span style= "FONT-SIZE:18PX;" >ofstream LogFile;                               Log file to be written assoccontainer<int> c;...for (Seqcontainer<int>::iterator i = C.begin (); I! = C.end ();// The third part of the For loop is empty, and I increments below. /* do nothing (*) {if (Badvalue (*i)) {logFile << "erasing" << *i << ' \ n ';//write log file <span style= "color: #ff0000 ;" >i = C.erase (i); </span>//to bad value, put current I to erase, increment i is side effect}else ++i; For good values, the}</span> is simply incremented

Maybe you want to know how to use the list. In terms of traversal and deletion, you can treat a list as a vector/string/deque, or you can treat it as a closed container. Both methods are applicable to lists. The general practice is to use the same way as vectors, strings, and deque for lists.






Careful selection of methods to delete elements

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.