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.)
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.
To remove all copies of an element from a vector , you can use std::remove like this: v. erase(std::remove(v. begin(), v.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With