Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing Empty Elements from a Vector of Strings

Tags:

c++

string

vector

I'm attempting to make a small program that processes INI files, for use in a later project, first by reducing its size once loaded into memory. Thus,

where vLine is a vector containing the file contents

for (unsigned int i = 0; i < vLine.size(); i++)
{
   if (!vLine[i].find(';', 0))
   {
       vLine[i].erase();
   }
}

Upon printing vLine, I'll be left with spaces where once a line beginning with a semi-colon existed, such as

1.    
2. property
3. property
4. 
5. property

Using resize() appears to remove the last element from the list rather than remove these empty portions. The same problem exists where I remove lines that only contain whitespace with erase().

Is it possible to remove these empty elements while preserving the order of vLine?

(Apologies for not using iterators in this.)

like image 563
JGrey Avatar asked Oct 07 '11 02:10

JGrey


People also ask

How do I remove blank strings from a vector in R?

stri_remove_empty (alias stri_omit_empty ) removes all empty strings from a character vector, and, if na_empty is TRUE , also gets rid of all missing values. stri_remove_empty_na (alias stri_omit_empty_na ) removes both empty strings and missing values.

How do you clear a vector string?

To remove all copies of an element from a vector , you can use std::remove like this: v. erase(std::remove(v. begin(), v.

How do you remove values from a vector?

All the elements of the vector are removed using clear() function. erase() function, on the other hand, is used to remove specific elements from the container or a range of elements from the container, thus reducing its size by the number of elements removed.


1 Answers

This:

vLine[i].erase(); 

does not erase vLine[i] from the vector. The expression vLine[i] returns a reference to the element at index i. So assuming that vLine is of type std::vector<std::string>, the function call erase() actually calls string::erase() on the element, not vector::erase() on the vector. All you're doing is making that particular element blank.

What you probably want is something like this:

vLine.erase(vLine.begin() + i);

This actually removes the element from the vector. Now, this does invalidate all current iterators to the vector, and the indices won't be right anymore. This is a situation where you really need to use iterators.

std::vector<std::string>::iterator i = vLine.begin();
while(i != vLine.end())
{
    if(i->find(';', 0) != std::string::npos)
    {
        i = vLine.erase(i);
    }
    else
    {
        ++i;
    }
}

But there's an even easier way to do this: use the standard algorithm std::remove_if() with a functor then call vLine.erase().

struct HasSemicolon
{
    bool operator()(const std::string& s)
    {
        return s.find(';', 0) != std::string::npos;
    }
};

// ...

vLine.erase(std::remove_if(vLine.begin(), vLine.end(), HasSemicolon()), vLine.end());

If you can use a C++11 compiler, then you can also use lambda expressions to be even more concise.

like image 103
In silico Avatar answered Oct 18 '22 14:10

In silico