Removing all empty elements in a vector from end

2019-07-13 15:24发布

问题:

Given a std::vector of strings, what is the best way of removing all elements starting from the end that are empty (equal to empty string or whitespace). The removal of elements should stop when a non-empty element is found.

My current method, (work in progress) is something like:

while (Vec.size() > 0 && (Vec.back().size() == 0 || is_whitespace(Vec.back()))
{
    Vec.pop_back();
}

where is_whitespace returns a bool stating if a string is whitespace or not

I suspect that my method will resize the vector at each iteration and that is suboptimal. Maybe with some algorithm it is possible to do in one step.

Input: { "A", "B", " ", "D", "E", " ", "", " " }

Desired Output: { "A", "B", " ", "D", "E" }

回答1:

As I did not find a good dupe on first glance, here is a simple solution:

// Helper function to see if string is all whitespace
// Can also be implemented as free-function for readablity and
// reusability of course
auto stringIsWhitespace = [](const auto &str)
{
    return std::all_of(
        begin(str), end(str), [](unsigned char c) { return std::isspace(c); });
};

// Find first non-whitespace string from the back
auto it = std::find_if_not(rbegin(Vec), rend(Vec), stringIsWhitespace);
// Erase from there to the end
Vec.erase(it.base(), end(Vec));

Note the unsigned in the lambda due to this gotcha.

Live example thanks to @Killzone Kid.



回答2:

Here's a better way:

for (auto it = Vec.rbegin(); it != Vec.rend() && is_whitespace(*it); )
{
    it = Vec.erase(it);
}

It will start from the end and stop once non-whitespace has been encountered or the beginning of the vector is reached, whichever comes first. Note that I don't increment the iterator in the for loop.