3

I know how do erase elements of a list, and that erase return a valid iterater. My problem is, that I want to remove not just one element but multiple.

Actuall my code is like

 for(list<Treenode*>::iterator it=currentLevel->begin(); it!=currentLevel->end(); ++it){
     if(something(*it))  {
         for(list<Treenode*>::iterator it2=currentNewLevel->begin();it2!=currentNewLevel->end();){
             if (somethingDifferent(*it2)) {
                 it2=currentLevel->erase(it2);
             } else {
                 ++it2;
             }
         }
     }
 }

of course this could not work, because it is not changed. I don't know how to change the iterator but stay on this iteration-step.

Thank you for reading. I hope someone know the answer.

Pierre Fourgeaud
  • 14,290
  • 1
  • 38
  • 62
Name
  • 33
  • 1
  • 3
  • Maybe I am simple minded: if(it2 == it) adjust it, too, after erase –  Aug 18 '13 at 09:12

2 Answers2

4

In general, the way to remove elements from a list based depending on a condition is to use the std::list::remove_if member function.

bool pred(const Treenode* t) { .... }
currentNewLevel.remove_if(pred);

The predicate can be a functor, so it can keep any state that is required to implement the removal criteria:

#include <algorithm> // for std::find_if
#include <list>

// unary predicate functor. Returns true if an element of a reference
// list satisfies "something" and the functor call argument satisfies "somethingDifferent"
struct Pred
{
  Pred(const std::list<Treenode*>& nodes) : nodes_(nodes) {}
  bool (const Treenode* t) const
  {
    return std::find_if(nodes_.begin(), nodes_.end(), something) != nodes_.end() &&
           somethingDifferent(t);
  }
 private:
  const std::list<Treenode*>& nodes_;
};

then

Pred p(currentLevel);
currentLevel.remove_if(p);
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Thank you. The problem is I do some other stuff in the outer loop. I could use your way for the inner loop but than the iterator of the outer loop would not be valid. – Name Aug 18 '13 at 08:48
  • @user2693497 you could write a functor that uses `currentLevel`. And I don't really see the problem with the outer loop iterator. You should probably explain what you are trying to achieve. – juanchopanza Aug 18 '13 at 08:54
  • @Name I added an example with a functor. It does what I think your original code was trying to do. – juanchopanza Aug 18 '13 at 09:08
  • thank you again. the "if(SomethinDifferent){...} " part is just a little part of what I do for each list-entry. I do a lot of stuff that change the other list-entrys eventually. the changed list-entrys should not be visited by the iterator. So I want to remove them from currentLevel. So I really need the outer loop. I thougt wenn removing elements from a list I iterate I get a segmentation-fault. But this is only true when removing the element the iterator shows at at the moment. So I only have to make sure I do not remove this element. Thanks for help! – Name Aug 18 '13 at 09:28
0

do while loop. it's mostly ++ too so the performance should be good.

std::vector<PdfTextRegion*>::const_iterator textRegion = m_pdfTextRegions.begin();
    while(textRegion != m_pdfTextRegions.end())        
    {
        if ((*textRegion)->glyphs.empty())
        {
            m_pdfTextRegions.erase(textRegion);
            textRegion = m_pdfTextRegions.begin();
        }
        else
            textRegion++;
    }
  • The performance can easily be horrible - worst case _O(n**2)_, since it starts from the beginning every time. The `remove_if` version, which swaps the targeted elements to the end, is guaranteed linear time and single-pass. It's better in absolutely every way. – Useless Jul 12 '20 at 20:50