Удаление пустых элементов из вектора строк - PullRequest
10 голосов
/ 07 октября 2011

Я пытаюсь создать небольшую программу, которая обрабатывает INI-файлы, для использования в более позднем проекте, сначала уменьшив его размер после загрузки в память. Таким образом,

где vLine - вектор, содержащий содержимое файла

for (unsigned int i = 0; i < vLine.size(); i++)
{
   if (!vLine[i].find(';', 0))
   {
       vLine[i].erase();
   }
}

После печати vLine у ​​меня останутся пробелы, в которых когда-то существовала строка, начинающаяся с точки с запятой, например

1.    
2. property
3. property
4. 
5. property

Использование resize () появляется для удаления последнего элемента из списка, а не для удаления этих пустых частей. Та же проблема существует, когда я удаляю строки, которые содержат только пробелы, с помощью erase ().

Можно ли удалить эти пустые элементы при сохранении порядка vLine?

(Извините, что не использовал итераторы в этом.)

Ответы [ 3 ]

10 голосов
/ 07 октября 2011

Это:

vLine[i].erase(); 

не стирает vLine[i] из вектора.Выражение vLine[i] возвращает ссылку на элемент с индексом i.Таким образом, предполагая, что vLine имеет тип std::vector<std::string>, вызов функции erase() фактически вызывает string::erase() для элемента, а не vector::erase() для вектора.Все, что вы делаете, это делаете этот конкретный элемент пустым.

То, что вам, вероятно, нужно, выглядит примерно так:

vLine.erase(vLine.begin() + i);

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

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;
    }
}

Но есть еще более простой способ сделать это: использовать стандартный алгоритм std::remove_if() с функтором, а затем вызвать 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());

Если вы можете использовать компилятор C ++ 11, то вы также можете использовать лямбда-выражения, чтобы быть еще более кратким.

9 голосов
/ 07 октября 2011

Проблема в вашей логике для удаления элементов.Когда вы сталкиваетесь с элементом с индексом i, который хотите стереть, вы очищаете его значение, но не удаляете его из вектора.

Стандартный и простой способ сделать то, что вы хотите сделатьis std::remove_if:

vLine.erase(
    std::remove_if(
        vLine.begin(),
        vLine.end(),
        [](std::string const& s) { return s.size() != 0 && s.front() == ';'; }),
    vLine.end());
5 голосов
/ 07 октября 2011

Используйте идиому стирания / удаления, желательно с лямбдой из C ++ 11:

foo.erase(std::remove_if(foo.begin(), foo.end(), 
                         [](const std::string& s) 
                         { return s.find(';', 0); }));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...