【问题标题】:Removing Empty Elements from a Vector of Strings从字符串向量中删除空元素
【发布时间】:2011-12-02 16:55:28
【问题描述】:

我正在尝试制作一个处理 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顺序的同时去掉这些空元素?

(很抱歉在此没有使用迭代器。)

【问题讨论】:

  • 回复:(很抱歉在此不使用迭代器。) - 为什么不使用迭代器?
  • 对其正确使用缺乏了解。没有他们似乎(似乎?)可以做到这一点。
  • 您可以从向量中删除行,而不仅仅是删除字符串的内容(这是vLine[i].erase() 所做的,不是吗?调用vLine.erase(),因为它会从vector 中删除。然后重写文件输出。一个惯用的方法是 C++ 的 erase-remove idiom,尽管您可能希望使用 &lt;algorithm&gt; 中的 std::remove_if 来使用条件。

标签: c++ string vector


【解决方案1】:

这个:

vLine[i].erase(); 

不会从向量中删除vLine[i]。表达式vLine[i] 返回对索引i 处元素的引用。所以假设vLinestd::vector&lt;std::string&gt; 类型,函数调用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 编译器,那么你也可以使用 lambda 表达式来更简洁。

【讨论】:

  • 非常感谢,In Silico。我会花时间学习迭代器并相应地修改我的应用程序。
  • 您能添加一个使用 C++11 lambdas 的示例吗?一个小时以来,我一直在努力解决这个问题,但我在阅读 C++ 文档时感到很糟糕。
  • @QPaysTaxes en.cppreference.com/w/cpp/algorithm/remove 有一个带有 lambda 的示例。
【解决方案2】:

问题在于您删除元素的逻辑。当您在索引i 处遇到要擦除的元素时,您会清除其值,但不会将其从向量中移除。

做你想做的事情的标准和简单的方法是std::remove_if

vLine.erase(
    std::remove_if(
        vLine.begin(),
        vLine.end(),
        [](std::string const& s) { return s.size() != 0 && s.front() == ';'; }),
    vLine.end());

【讨论】:

    【解决方案3】:

    使用擦除/删除习语,最好使用来自 C++11 的 lambda:

    foo.erase(std::remove_if(foo.begin(), foo.end(), 
                             [](const std::string& s) 
                             { return s.find(';', 0); }));
    

    【讨论】:

    • 我认为{ return s.find(';', 0); })); 必须是:{ return s.find(';', 0); }), foo.end()); 否则空间似乎不会从 foo 中释放。至少这是我得到的结果。 @Mankarse 的回答(基本相同)似乎可以完成这项工作! :)
    猜你喜欢
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多