4

I have a std::list of Bananas, and I want to get rid of the bad ones. Is there any relatively simple way to perform the following pseudocode?

foreach(Banana banana in bananaList)
{
    if(banana.isBad()) bananaList.remove(banana);
}

(Making a transition from C# and Java to C++ has been a rocky road.)

2
  • 1
    stackoverflow.com/questions/1038708/… Commented Jul 19, 2010 at 20:31
  • @YuppieNetworking: The linked question works in the general case, but doesn't have the best solution for the case the OP has -- where he wants to remove an element iff a member function returns true. Commented Jul 19, 2010 at 20:32

3 Answers 3

7
bananaList.remove_if(std::mem_fun_ref(&Banana::isBad));

Note that you should probably be using std::vector instead of std::list though -- vector performs better in 99.9% of cases, and it's easier to work with.

EDIT: If you were using vectors, vectors don't have a remove_if member function, so you'd have to use the plain remove_if in namespace std:

bananaVector.erase(
    std::remove_if(bananaVector.begin(), bananaVector.end(), std::mem_fun_ref(&Banana::isBad)), 
    bananaVector.end());
Sign up to request clarification or add additional context in comments.

8 Comments

Really? I thought that if I was removing lots of things from the middle of the list then std::list was the way to go.
@John: std::list makes the removal itself fast (O(1)), but finding the right spot relatively slow (O(N), usually a higher constant than vector).
@John: Due to better cache locality, in practice std::vector often performs better where, in theory, std::list does. You'll have to measure.
@Martin York: For std::remove_if, you would be correct. However, for std::list<t>::remove_if the member function takes care of that for you.
I can't quote the article, but I read something in Dr. Dobbs or the C++UJ where they did some massive tests on list, vector, set, etc..., and they found that almost every time vector was faster. Even when the vector was being resized or removes and inserts were happening in the middle, it was still much faster, thanks to the rules of cache locality.
|
1

You'd typically do something like:

list.erase(std::remove_if(list.begin(), list.end(), std::mem_fun(Banana::isBad)), list.end());

Edit: Thanks to remove_if being implemented as a member function of std::list, Billy ONeal's answer is probably the better way to do the job as described, though this would be easier to convert when/if you decide to use a vector, deque, etc., which, as already discussed in comments, is probably a good thing to do.

Comments

0

You can use a homebrew code like

for(list<...>::iterator it=bananas.begin(); end=bananas.end(); it!=end;) {
  if(... decide ...) {
    it=bananas.erase(it);
  } else
    ++it;
}

or, you can use the list::remove_if method, or std::remove_if function (which is usable with a vector, too).

1 Comment

One should always prefer algorithms to explicit loops.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.