Delete strings in a vector

2019-07-31 14:33发布

问题:

I have a vector full of strings

the vector consistentWords contains 4 strings

  1. dedf
  2. eedf
  3. fedf
  4. hedf

Now I want to delete all the strings that words don't start with the letter d

However it ends up just deleting eedf and hedf and the result I have left is

  1. dedf
  2. fedf

My code:

    for(int q=0; q<consistentWords.size(); q++)
    {
        string theCurrentWord = consistentWords[q];
        if(theCurrentWord[0] != 'd')
        {
            consistentWords.erase(consistentWords.begin()+q);
        }
    }

Any thoughts? I just can't see why it's not deleting all of the strings that don't start with d.

回答1:

The problem is you are deleting elements from the vector and incrementing your index q in the same iteration. So in the 2nd iteration of your for loop, you erase "eedf" from you vector then your vector is ["dedf", "fedf", "hedf"] and q = 1. But then when you loop back to the begining of the for loop, q is incremented to 2 so you look at "hedf" next, skipping "fedf". To fix this you could decrement q when you remove an element from the array like so:

for(int q=0; q<consistentWords.size(); q++)
{
    string theCurrentWord = consistentWords[q];
    if(theCurrentWord[0] != 'd')
    {
        consistentWords.erase(consistentWords.begin()+q);
        --q;
    }
}

Or you could use iterators:

vector<string>::iterator it = consistentWords.begin()
while(it != consistentWord.end())
{
    string theCurrentWord = consistentWords[q];
    if(theCurrentWord[0] != 'd')
    {
        it = consistentWords.erase(it);
    }
    else
    {
        ++it;
    }
}

Note that erase returns an iterator to the element after the one you have erased. You must re-assign it because it becomes invalidated when the vector is resized.



回答2:

To start with, the strings correspond to these indices:

dedf 0
eedf 1
fedf 2
hedf 3

Let's say you delete eedf (so q == 1. After the delete, the vector looks like

dedf 0
fedf 1
hedf 2

But then q gets incremented to 2, completely skipping over fedf. The fix would be to alter the for loop slightly:

for(int q=0; q<consistentWords.size();)
{
    string theCurrentWord = consistentWords[q];
    if(theCurrentWord[0] != 'd')
    {
        consistentWords.erase(consistentWords.begin()+q);
    }
    else
    {
        q++;
    }
}

or something to the same effect.



回答3:

You are skipping elements. Assume you need to delete elements 5,6: when you delete element 5, element 6 becomes element 5 - and you skip it, since q was increased to 6,

The better way to do it is manually increasing q only when you do not delete an element



回答4:

When you erase you should not do q++. Then you miss one element.



回答5:

The question has been answered, but you should look into the Erase-remove idiom:

Example:

consistentWords.erase(
    std::remove_if(consistentWords.begin(), consistentWords.end(), 
    [](const std::string& s) -> bool { return (s[0] == 'd'); }),
    consistentWords.end());


回答6:

To remove the word:

consistentWords.erase(
    std::remove(consistentWords.begin(), consistentWords.end(), theCurrentWord),
    consistentWords.end()
);