CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 25
  1. #1
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    remove multiple elements from vector in a loop

    I have a vector,
    Code:
    std::vector<int> myVector;
    
    myVector[0] = 3;
    myVector[1] = 4;
    myVector[2] = 5;
    and I need to remove certain elements, in this case [1] and [2]. This is happening in a loop where some things are evaluated, and under certain circumstances, and element is removed.
    Code:
    for(i=0; i<myVector.size(); i++) {
       if(myVector[i] == 4 || myVector[i] == 5) {
          myVector.erase( myVector.begin()+i );
       }
    }
    the logic is simplified here. The output after this loop is,
    myVector.size() = 2
    myVector[0] = 3;
    myVector[1] = 5;

    As I read this, when myVector[i] == 3, control falls through and nothing happens. When myInt[i] == 4, myVector.begin()+i = 0+1 and myVector[1] is erased. When myVector[i] == 5, myVector.begin()+i = 0+2 and myVector[2] is erased. Element [2] doesn't exist anymore, so the value 5 remains on the list. Obviously I'm not using the iterator properly.

    The iterator position needs to be dynamic to take into account the changing size of the vector, but I can't see how to do that. This seems like a simple issue, so I presume I am missing something here. I can't just loop through and look for 4 or 5, the logic is more complex than that. I need to know how to recursively remove elements from a vector, taking into account the fact that the vector size changes.

    Maybe I need to loop differently. It's almost like I need to repeat the value of i in a case where a given i was removed. This has to work in larger vectors where the elements to be removed can occur in any element. I guess I could just set i=0 after each element is removed and repeat from the top, but that doesn't seem like the best solution either.

    LMHmedchem
    Last edited by LMHmedchem; May 18th, 2011 at 02:10 PM.

  2. #2
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: remove multiple elements from vector in a loop

    Didn't read the whole post, so sorry if this is the wrong answer, but when removing items in a loop from an index based container, it's easiest to start at the end and work backwards.

  3. #3
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: remove multiple elements from vector in a loop

    See remove_if
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  4. #4
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721

    Re: remove multiple elements from vector in a loop

    see the following post on using remove_if and removing elements
    while looping.

    http://www.codeguru.com/forum/showthread.php?t=475058

  5. #5
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: remove multiple elements from vector in a loop

    So it would appear I could do something like,
    Code:
    int remove;
    for(i=0; i<myVec.size(); i++) {
       if(myVec[i] == 4 || myVector[i] == 5) {
          remove_this = myVector[i];
          myVec.erase( remove(myVec.begin(),myVec.end(),remove_this) , myVec.end() );
       }
    }
    This seems to have the same problem as the first code I posted.
    myVector.size() = 2
    myVector[0] = 3;
    myVector[1] = 5;

    LMHmedchem

  6. #6
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: remove multiple elements from vector in a loop

    Code:
    myVec.erase(
        std::remove_if(myVec.begin(),myVec.end(), [](int i) { return i == 4 || i == 5; }),
        myVec.end());
    Or you can create an appropriate function or functor if your compiler does not support the lambda function I used above.

  7. #7
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: remove multiple elements from vector in a loop

    Quote Originally Posted by Lindley View Post
    Code:
    myVec.erase(
        std::remove_if(myVec.begin(),myVec.end(), [](int i) { return i == 4 || i == 5; }),
        myVec.end());
    Or you can create an appropriate function or functor if your compiler does not support the lambda function I used above.
    My complier doesn't like this, I get
    expected primary-expression before '[' token
    expected primary-expression before ']' token
    expected primary-expression before "int"

    It seems as if I need a function that returns the values for what I need to remove?

    LMHmedchem

  8. #8
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: remove multiple elements from vector in a loop

    geez. you mean like this? Lindley did say that the lamda expression might not work for you. In that case write a global function, static member function of a class, or a functor.

    Code:
    // write a global function
    void RemoveTheseValues
    { 
       return(i == 4 || i == 5);
    }
    
    // or write a functor
    struct RemoveTheseValues
    {
       bool operator() (int i)
       { 
          return(i == 4 || i == 5);
       }
    };
    See here for even more examples.
    http://www.cplusplus.com/reference/algorithm/remove_if/

  9. #9
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: remove multiple elements from vector in a loop

    Well I'm going to have to go with this, for lack of being able to get anything else working,
    Code:
    for(i=0; i<myVector.size(); i++) {
       if(myVector[i] == 4 || myVector[i] == 5) {
          int remove = myVector[i];
          myVector.erase( remove(myVector.begin(), myVector.end(), remove), myVector.end() );
          i = 0;
       }
    }
    It will cost an extra iteration through the loop or so, but these vecs will never have more than two or three elements. Perhaps I should have just looked at removing elements starting from the back of the vector as GCDEF suggested.

    Quote Originally Posted by kempofighter View Post
    geez. you mean like this? Lindley did say that the lamda expression might not work for you. In that case write a global function, static member function of a class, or a functor.

    Code:
    // write a global function
    void RemoveTheseValues
    { 
       return(i == 4 || i == 5);
    }
    
    // or write a functor
    struct RemoveTheseValues
    {
       bool operator() (int i)
       { 
          return(i == 4 || i == 5);
       }
    };
    See here for even more examples.
    http://www.cplusplus.com/reference/algorithm/remove_if/
    I tried quite a few versions of things like this, but I couldn't get any of them to compile. I just can't spend all afternoon trying to improve on something this simple. It would be nice if there was a version of the stl documentation that wasn't written in ancient Greek. Maybe I'm just a moron, but I don't find things like, "Unary predicate taking an element in the range as argument, and returning a value indicating the falsehood (with false, or a zero value) or truth (true, or non-zero) of some condition applied to it. This can either be a pointer to a function or an object whose class overloads operator()" to be very helpful if you weren't a CS major, which I wasn't. English is a nice language too.

    LMHmedchem
    Last edited by LMHmedchem; May 18th, 2011 at 05:30 PM.

  10. #10
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: remove multiple elements from vector in a loop

    Quote Originally Posted by LMHmedchem View Post
    So it would appear I could do something like,
    Code:
    int remove;
    for(i=0; i<myVec.size(); i++) {
       if(myVec[i] == 4 || myVector[i] == 5) {
          remove_this = myVector[i];
          myVec.erase( remove(myVec.begin(),myVec.end(),remove_this) , myVec.end() );
       }
    }
    This seems to have the same problem as the first code I posted.
    myVector.size() = 2
    myVector[0] = 3;
    myVector[1] = 5;

    LMHmedchem
    The problem is obviously that you are still decreasing the size of the vector within the loop. Don't do that. The loop will end up terminating before all of the values are tested. When the loop tests the size again, it'll be shorter.

  11. #11
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Lightbulb Re: remove multiple elements from vector in a loop

    Quote Originally Posted by LMHmedchem View Post
    Well I'm going to have to go with this, for lack of being able to get anything else working,
    Code:
    for(i=0; i<myVector.size(); i++) {
       if(myVector[i] == 4 || myVector[i] == 5) {
          int remove = myVector[i];
          myVector.erase( remove(myVector.begin(), myVector.end(), remove), myVector.end() );
          i = 0;
       }
    }
    It will cost an extra iteration through the loop or so, but I can't spend all afternoon trying to improve on something this simple. Perhaps I should have just looked at removing elements starting from the back of the vector as GCDEF suggested.

    LMHmedchem
    It really is not that hard to tweak what lindley posted. All you have to do is write the global function and substitute its name where the lamda expression went (that is the 3rd argument to remove_if). It's that simple. If you can't do that in 10 minutes then you deserve an F on your assignment.

  12. #12
    Join Date
    May 2009
    Location
    Boston
    Posts
    364

    Re: remove multiple elements from vector in a loop

    Quote Originally Posted by kempofighter View Post
    The problem is obviously that you are still decreasing the size of the vector within the loop. Don't do that. The loop will end up terminating before all of the values are tested. When the loop tests the size again, it'll be shorter.
    I tried storing the values to remove in another vector, but of course I ended up looping though that as well. I need one of these remove_if methods that I can pass a range to and a value to remove, but no joy so far on that.

    LMHmedchem

  13. #13
    Join Date
    Aug 2005
    Location
    San Diego, CA
    Posts
    1,054

    Re: remove multiple elements from vector in a loop

    Quote Originally Posted by LMHmedchem View Post
    Well I'm going to have to go with this, for lack of being able to get anything else working,
    Code:
    for(i=0; i<myVector.size(); i++) {
       if(myVector[i] == 4 || myVector[i] == 5) {
          int remove = myVector[i];
          myVector.erase( remove(myVector.begin(), myVector.end(), remove), myVector.end() );
          i = 0;
       }
    }
    It will cost an extra iteration through the loop or so, but these vecs will never have more than two or three elements. Perhaps I should have just looked at removing elements starting from the back of the vector as GCDEF suggested.



    I tried quite a few versions of things like this, but I couldn't get any of them to compile. I just can't spend all afternoon trying to improve on something this simple. It would be nice if there was a version of the stl documentation that wasn't written in ancient Greek. Maybe I'm just a moron, but I don't find things like, "Unary predicate taking an element in the range as argument, and returning a value indicating the falsehood (with false, or a zero value) or truth (true, or non-zero) of some condition applied to it. This can either be a pointer to a function or an object whose class overloads operator()" to be very helpful if you weren't a CS major, which I wasn't. English is a nice language too.

    LMHmedchem
    Did you look at the example? You could have copy and pasted the example from that link and compiled it. Simply substitute your function names.

  14. #14
    Join Date
    Apr 1999
    Posts
    27,449

    Re: remove multiple elements from vector in a loop

    Quote Originally Posted by LMHmedchem View Post
    I have a vector,
    Code:
    std::vector<int> myVector;
    
    myVector[0] = 3;
    myVector[1] = 4;
    myVector[2] = 5;
    and I need to remove certain elements, in this case [1] and [2]. This is happening in a loop where some things are evaluated, and under certain circumstances, and element is removed.
    Code:
    #include <algorithm>
    #include <vector>
    #include <iostream>
    
    bool RemoveMe(int val)
    {
       return ( val == 3 || val == 4);
    }
    
    int main()
    {
        std::vector<int> vect(3);
        vect[0] = 3;
        vect[1] = 4;
        vect[2] = 5;
        vect.erase(std::remove_if(vect.begin(), vect.end(), RemoveMe), vect.end());
        for (size_t i = 0; i < vect.size(); ++i )
             std::cout << vect[i] << "\n";
    }
    Is this what you're trying to code?

    But in general, if you're writing convoluted loops to remove elements from a container in C++, then you need to take a step back and rethink what you're doing, as more than likely, an alogrithm or set of algorithm functions will do the job, safely and correctly.

    Regards,

    Paul McKenzie

  15. #15
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: remove multiple elements from vector in a loop

    Quote Originally Posted by LMHmedchem View Post
    It would be nice if there was a version of the stl documentation that wasn't written in ancient Greek. Maybe I'm just a moron, but I don't find things like, "Unary predicate taking an element in the range as argument, and returning a value indicating the falsehood (with false, or a zero value) or truth (true, or non-zero) of some condition applied to it. This can either be a pointer to a function or an object whose class overloads operator()" to be very helpful if you weren't a CS major, which I wasn't. English is a nice language too.
    You just have to get used to the terminology. All me to translate:

    "Unary predicate (function taking one argument) taking an element in the range as argument (the function's argument type must match the type in the container), and returning a value indicating the falsehood (with false, or a zero value) or truth (true, or non-zero) of some condition applied to it (the function must return a bool indicating whether or not to remove the element in question). This can either be a pointer to a function or an object whose class overloads operator() (You can specify the function several different ways.)"

    Such formal language can have a learning curve, but its preciseness is useful when you want to know exactly what a container or algorithm is going to do.
    Last edited by Lindley; May 18th, 2011 at 10:02 PM.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured