3

I am trying to delete empty entries from std::vector. Here is a sample code, but something is wrong here.

#include <iostream>
#include <string>
#include<vector>
#include <cctype>

int main()
{
    std::vector<std::string> s1 = {"a"," ", "", "b","c","   ","d"};
    for (auto it = s1.begin(); it != s1.end() && isspace(*it); )
{
        it = s1.erase(it);
}

    std::cout<<"vector size = "<<s1.size();
    for (auto &i:s1) 
        std::cout<<i<<"\n";      

}

I am running a for loop to find out empty elements and deleting from there. There should be STL method too, but not sure how it will work.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
ewr3243
  • 397
  • 3
  • 19
  • 3
    [`isspace()`](https://en.cppreference.com/w/cpp/string/byte/isspace) expects an `int` (historically, but actually a character) but you provide a `std::string`. That's not compatible. You could check instead `(*it == "" || *it == " ")`. – Scheff's Cat Feb 06 '20 at 18:08
  • 3
    Your `for` loop tries to delete "empty" entries only from the beginning of the `vector`. As soon as it encounters a single non-"empty" entry - it stops. – Algirdas Preidžius Feb 06 '20 at 18:08
  • 1
    When you think "something is wrong", you should think about *why* you think something is wrong. Does it compile or not? Is there a compilation error? If not, does it behave as you expected? How do you expect it to behave? How does it behave? – eerorika Feb 06 '20 at 18:09
  • https://en.cppreference.com/w/cpp/algorithm/remove and https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom – Kenny Ostrom Feb 06 '20 at 18:16
  • 1
    `std::remove_if` is what you're looking for. – PaulMcKenzie Feb 06 '20 at 18:19

1 Answers1

4

It seems you mean the following

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

int main() 
{
    std::vector<std::string> v = { "a", " ", "", "b", "c", "   ", "d" };

    auto is_empty = []( const std::string &s )
    {
        return s.find_first_not_of( " \t" ) == std::string::npos;
    };

    v.erase( std::remove_if( std::begin( v ), std::end( v ), is_empty ), std::end( v ) );

    for ( const auto &s : v )
    {
        std::cout << "\"" << s << "\" ";
    }
    std::cout << std::endl;

    return 0;
}

The program output is

"a" "b" "c" "d" 

As for your code then it is inefficient because you are trying to remove each found element separately and this loop for example

for (auto it = s1.begin(); it != s1.end() && isspace(*it); )
{
    it = s1.erase(it);
}

can iterate never because the first element is not satisfies the condition isspace(*it) that moreover is invalid. That is you are supplying an object of the type std::string to a function that expects an object of the type char (more precisely of the type int).

If to use the C function isspace then the program can look the following way.

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cctype>

int main() 
{
    std::vector<std::string> v = { "a", " ", "", "b", "c", "   ", "d" };

    auto is_empty = []( const std::string &s )
    {
        return std::all_of( std::begin( s ), std::end( s ), 
                            []( char c ) 
                            { 
                                return std::isspace( ( unsigned char )c );
                            } );
    };

    v.erase( std::remove_if( std::begin( v ), std::end( v ), is_empty ), std::end( v ) );

    for ( const auto &s : v )
    {
        std::cout << "\"" << s << "\" ";
    }
    std::cout << std::endl;

    return 0;
}

The program output is the same as shown above.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335