Обрезка вектора строк - PullRequest
       5

Обрезка вектора строк

4 голосов
/ 10 января 2011

У меня есть std::vector из std::strings, содержащее данные, подобные этим:

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

Как я могу получить вектор, содержащий 4 строки от 1 до 4?(т.е. я хочу обрезать все пустые строки из начала и конца вектора):

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

В настоящее время я использую прямой итератор, чтобы перейти на "Abc", и обратный итератор, чтобывернусь к "Ghi", а затем построю новый вектор, используя эти итераторы.Этот метод работает, но я хочу знать, есть ли более простой способ обрезать эти элементы.

PS Я нуб C ++.

Редактировать

Также яследует упомянуть, что вектор может состоять полностью из пустых строк, и в этом случае вектор с размером 0 будет желаемым результатом.

Ответы [ 5 ]

2 голосов
/ 10 января 2011

Как насчет этого с предикатом:

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

Теперь, чтобы урезать:

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()));

Возможно, при вызове .base() может быть один за другим, но общая идея должна работать.

0 голосов
/ 07 июня 2011

Итераторы, безусловно, путь.Они делают код намного более читабельным и интуитивно понятным.

#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 голосов
/ 10 января 2011
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"

Из любопытства хотелось бы увидеть ваш код с использованием обратного итератора.Я не понимаю, как вы строите новый вектор из двух итераторов, которые имеют разные направления.

0 голосов
/ 10 января 2011

То, что вы сделали, хорошо.Но если вы хотите сократить один контейнер "на месте", а не сделать копию поддиапазона, вы можете erase другие диапазоны из 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);
}

Но я согласен с @Натан: Если то, что у вас уже есть, имеет для вас больше смысла, чем это, сохраните его, если вы не знаете или не подозреваете, что в нем будет задействовано очень много строк.

0 голосов
/ 10 января 2011

Ваш подход разумен. Другой подход состоит в том, чтобы найти первую строку, а затем скопировать все последовательные строки в начальный (и последующий) элементы вектора, после чего вы обрезаете конец вектора.

Если это не критически важный кусок кода, который замедляет работу вашего приложения, важно, чтобы оно работало, а не чтобы вы имели наиболее эффективную реализацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...