Trimming Vector Rows

I have a std::vector of std::strings containing data similar to this:

 [0] = "" [1] = "Abc" [2] = "Def" [3] = "" [4] = "Ghi" [5] = "" [6] = "" 

How can I get a vector containing 4 lines from 1 to 4? (i.e. I want to trim all empty lines from the beginning and end of the vector):

 [0] = "Abc" [1] = "Def" [2] = "" [3] = "Ghi" 

I am currently using a formatted iterator to go to "Abc" and the reverse iterator to go back to "Ghi" and then create a new vector using these iterators. This method works, but I want to know if there is an easier way to crop these elements.

PS I am C ++ noob.

Edit

In addition, I must mention that a vector can consist entirely of empty strings, in which case a vector of size 0 is the desired result.

+4
source share
5 answers

How about this, with the predicate:

 class StringNotEmpty { bool operator()(const std::string& s) { return !s.empty(); } }; 

Now crop:

 vec.erase(std::find_if(vec.rbegin(), vec.rend(), StringNotEmpty()).base(), vec.end()); vec.erase(vec.begin(), std::find_if(vec.begin(), vec.end(), StringNotEmpty())); 

The call to .base() may be different, but the general idea should work.

+2
source

Your approach is reasonable. Another approach is to find the first line, and then copy all consecutive lines to the beginning (and subsequent) elements in the vector, after which you crop the end of the vector.

If this is not a critical piece of code that slows down your application, it matters more than it is possible that you can implement it most efficiently.

0
source

What you did is good. But if you want to shorten one container "in place" rather than make a copy of the subrange, you can erase other ranges from vector .

 // Probably similar to what you already have: Find iterators for the range to keep. std::vector<std::string>::iterator start=strs.begin(), stop=strs.end(); start = strs.begin(); while (start != stop && start->empty()) ++start; if (start == stop) { // all strings were empty! strs.clear(); } else { while (start != --stop && stop->empty()) ; ++stop; // std::vector<std::string>(start, stop) is the desired subrange strs.erase(stop, strs.end()); strs.erase(strs.begin(), start); } 

But I agree with @Nathan: If you have more sense for you than that, save it if you do not know or suspect that a huge number of lines will be involved.

0
source
 typedef std::vector<std::strings> Strings; Strings myStrings; //... currently myStrings contains "","Abc","Def","","Ghi","","" Strings::iterator itNewBegin = myStrings.begin(); Strings::iterator itNewEnd = myStrings.end(); std::advance(itNewBegin,1); std::advance(itNewEnd,4); String myTrimmedStrings(itNewBegin,itNewEnd); //... currently myTrimmedStringscontains "Abc","Def","","Ghi" 

Out of curiosity, I would like to see your code using a reverse iterator. I don’t understand how you construct a new vector from two iterators having different directions.

0
source

Iterators are definitely the way to go. They make the code more readable and intuitive.

 #include <algorithm> typedef std::vector<std::string> strVec_t; bool notEmpty(std::string s){ return !s.empty(); } void trim(strVec_t& vec){ //get the first and last non-empty elements strVec_t::const_iterator first = std::find_if(vec.begin(), vec.end(), notEmpty); strVec_t::const_reverse_iterator last = std::find_if(vec.rbegin(), vec.rend(), notEmpty); //if every element is an empty string, delete them all if (first == vec.end()){ vec.clear(); //make a new vector from the first to the last non-empty elements } else { vec = strVec_t(first, last.base()); } } 
0
source

Source: https://habr.com/ru/post/1334858/


All Articles