deleting selected elements in a vector

This is a discussion on deleting selected elements in a vector within the C++ Programming forums, part of the General Programming Boards category; I want to go through a vector and delete any strings that contain nothing. ex: a vector containing: >one < ...

  1. #1
    Registered User
    Join Date
    May 2005
    Location
    Toronto, Canada
    Posts
    257

    deleting selected elements in a vector

    I want to go through a vector and delete any strings that contain nothing.
    ex: a vector containing:
    >one <
    ><
    >two <
    >three<

    I want to get rid of the >< elemnt and have only :
    >one <
    >two <
    >three<

    I tried this:
    Code:
    for (i=0; i<4; i++)
    	{
    		
    
    		if(vars.vectParmSelected[i].ParamName[0] == '\0')
    			vars.vectParmSelected.erase(i);	
    	}
    and
    Code:
    struct structLink
    {
    	CString ParamName;
    	int Index;
    };
    Code:
    vector <structLink> vectParmSelected;
    i get an error
    Code:
    error C2664: 'struct structLink *__thiscall std::vector<struct structLink,
    class std::allocator<struct structLink> >::erase(struct structLink *)' : cannot
     convert parameter 1 from 'int' to 'struct structLink *'
    But I do want to delete the whole structure at position i. How would this be fixed?

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    You cannot use an index when erasing from a vector. You should traverse through the vector using iterators and pass an iterator to erase. Save the return value of erase instead of incrementing the iterator (this means you should not have the ++iter at the end of your for loop, but instead only do it if the item was not erased).

    You should use the IsEmpty() function of CString to determine if it is empty instead of checking the first character.

    If you want to use indexes instead of iterators, you would want to use std::advance to get an iterator to the correct spot. If you do this, you'll have to remember to not increment your index if you actually erase something (or you will skip over one spot). Also remember to call size() on the vector in each pass through the loop because erasing will change the size and you might go past the vector's boundaries.

  3. #3
    C/C++Newbie Antigloss's Avatar
    Join Date
    May 2005
    Posts
    212
    use iterator
    maybe this could help
    Code:
    for ( std::vector<structLink>::iterator iter = vars.vectParmSelected.begin();
               iter != vars.vectParmSelected.end(); ++iter ) {
        if(vars.(*iter).ParamName[0] == '\0')
            iter = vars.vectParmSelected.erase(iter);
    }

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    Antigloss, your code skips the entry right after an erased entry. I would use remove_if, but if I was doing a loop I might change it to this:
    Code:
    for ( std::vector<structLink>::iterator iter = vars.vectParmSelected.begin();
    	 iter != vars.vectParmSelected.end(); )
    {
    	if(iter->ParamName.IsEmpty())
    		iter = vars.vectParmSelected.erase(iter);
    	else
    		++iter;
    }

  5. #5
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,794
    Code:
    #include <vector>
    #include <string>
    #include <functional>
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    
    using namespace std;
    
    int main()
    {
        vector<string> strVect;
    
        strVect.push_back("One");
        strVect.push_back("");
        strVect.push_back("Two");
        strVect.push_back("Three");
        strVect.push_back("");
        strVect.push_back("Four");
    
        // Print original vector contents
        copy( strVect.begin(), strVect.end(), ostream_iterator<string>(cout,"\n") );
    
        // Erase empty string elements from the vector
        vector<string>::iterator start;
        start = remove_if( strVect.begin(), strVect.end(), bind1st( equal_to<string>(), string("") ) );
        strVect.erase( start, strVect.end() );
    
        // Print modified vector contents
        cout << "****\n";
        copy( strVect.begin(), strVect.end(), ostream_iterator<string>(cout,"\n") );
    
        return 0;
    }
    Output:
    Code:
    One
    
    Two
    Three
    
    Four
    ****
    One
    Two
    Three
    Four
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  6. #6
    Registered User
    Join Date
    May 2005
    Location
    Toronto, Canada
    Posts
    257
    I got this working:
    Code:
    vector <structLink>::iterator iterator = vars.vectParmSelected.begin();
    
    	do       
    	{
    		if(iterator->ParamName.IsEmpty())
    			iterator = vars.vectParmSelected.erase(iterator);
    		else
    			++iterator;
    
    	}
    	while(iterator != vars.vectParmSelected.end());
    any pitfalls I may get myself into with this?

    >> start = remove_if( strVect.begin(), strVect.end(), bind1st( equal_to<string>(), string("") ) );

    It was a bit hard to figure this bit out. So I used the easier one above.
    Thanks a lot.
    Everything is relative...

  7. #7
    Magically delicious LuckY's Avatar
    Join Date
    Oct 2001
    Posts
    856
    I like hk_mp5kpdw's solution best of all, and traversing with an iterator is another preferred method (although you'll find that using a while loop is more accurate than your do-while because yours will execute the body once even if the vector's empty), but, as food for thought, here's another solution to consider:
    Code:
    for (int i = 0; i < vars.vectParmSelected.size(); ++i) {
      if (vars.vectParmSelected[i].IsEmpty())
        vars.vectParmSelected.erase(vars.vectParmSelected.begin() + i--);	
    }
    [edit]
    It's really weird the way the board is magically inserting those spaces before begin()
    Last edited by LuckY; 07-15-2005 at 12:23 PM.

  8. #8
    Registered User
    Join Date
    May 2005
    Location
    Toronto, Canada
    Posts
    257
    Actually, I just found a problem with the code, it doesn't erase all the empty cells. Or maybe I print wrong. I use this code
    Code:
    do       
    	{
    		if(iterator->ParamName.IsEmpty())
    			iterator = vars.vectParmSelected.erase(iterator);
    		else
    			++iterator;
    
    	}
    	while(iterator != vars.vectParmSelected.end());
    
    	for(i=0; i<vars.vectParmSelected.size(); i++)
    		fprintf(out, ">%s< ", vars.vectParmSelected[i].ParamName); // print params
    and the output is:
    Code:
    >BARO    < >< >  < >< >< ><
    it should only be >BARO <

    so it doesn't always see an empty entry in the vector.
    Last edited by earth_angel; 07-15-2005 at 12:06 PM.
    Everything is relative...

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    It should be a while loop, not a do while loop, in case the vector is empty already.

    If you do the output before the erasing, and then again after, what does it look like? The code looks fine.

    Another problem might be that the CString IsEmpty function is not returning the correct result. This might be the case because of the stuff you were doing with GetBuffer earlier.

    Step through the code with the debugger and see if the empty strings actually get erased.

  10. #10
    Registered User
    Join Date
    May 2005
    Location
    Toronto, Canada
    Posts
    257
    It seems fine now. I didn't notice but I was putting the spaces in the fields that I extracted the original vector from instead of erasing them completely. I;m impressed that you remember what I was warking on. and I actually re-wrote that function and this is my way aroud the empty edit boxes thing.

    A bit off topic. if a string contains >baro< and I try comparing it to >baro <, it obviously returns false. Is there a pailess way to get the number of chars to compare fro mthe second string (minus the spaces) ? I can't go the other way and use the length of the >baro< string, because there may be things that have the same first # characters.
    Everything is relative...

  11. #11
    Magically delicious LuckY's Avatar
    Join Date
    Oct 2001
    Posts
    856
    You can use TrimLeft() and TrimRight() to snip off leading and trailing space.

  12. #12
    Registered User
    Join Date
    May 2005
    Location
    Toronto, Canada
    Posts
    257
    Thanks,

    AS.
    Everything is relative...

  13. #13
    dra
    dra is offline
    Weak. dra's Avatar
    Join Date
    Apr 2005
    Posts
    166
    If you're not going to be making use of a vector's indexing feature in your program though, use a list instead. erasing objects from a list is much quicker than erasing from a vector.

  14. #14
    aoeuhtns
    Join Date
    Jul 2005
    Posts
    581
    Use the remove_if solution given by hk_mp or a variant. Its runtime is O(n) instead of O(n*n) (which the .erase()-using solutions used). The runtime would be O(n) for lists as well. Erasing an individual object from a list is faster than removing an individual object from a vector (O(1) instead of O(n)), but remove_if is clever.
    Last edited by Rashakil Fol; 07-15-2005 at 10:29 PM.

  15. #15
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    With small data sets it is better to go ahead and use vector as it has a smaller time constant factor among other reasons. See Item 76 of C++ Coding Standards for more information. In this case since the size of the vector is related to the number of edit controls, I doubt there will be enough elements to warrant a change. Correctness is much more important than speed here.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. can some one please tell me the cause of the error ?
    By broli86 in forum C Programming
    Replies: 8
    Last Post: 06-26-2008, 08:36 PM
  2. syntax help?
    By scoobygoo in forum C++ Programming
    Replies: 1
    Last Post: 08-07-2007, 10:38 AM
  3. Randomly rearranging the elements in a vector
    By Signifier in forum C++ Programming
    Replies: 11
    Last Post: 08-01-2007, 12:21 PM
  4. deleting elements of a vector
    By strickey in forum C++ Programming
    Replies: 11
    Last Post: 02-09-2005, 10:19 AM
  5. Certain functions
    By Lurker in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2003, 12:26 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21