从大向量中删除字符串列表的有效方法

时间:2013-12-22 02:38:20

标签: c++ stl

我正在使用visual studio 2012(windows),我正在尝试编写一个高效的c ++函数来从一个大的字符串向量中删除一些单词。

我正在使用stl算法。我是一名c ++初学者,所以我不确定这是最好的方法。这就是我所做的:

#include <algorithm>
#include <unordered_set>
using std::vector;

vector<std::string> stripWords(vector<std::string>& input, 
                               std::tr1::unordered_set<std::string>& toRemove){ 
     input.erase(
         remove_if(input.begin(), input.end(), 
                     [&toRemove](std::string x) -> bool {
                         return toRemove.find(x) != toRemove.end();
                     }));
     return input;
}

但是这不起作用,它不会遍历所有输入向量。

这是我如何测试我的代码:

vector<std::string>  in_tokens;
in_tokens.push_back("removeme");
in_tokens.push_back("keep");
in_tokens.push_back("removeme1");
in_tokens.push_back("removeme1");
std::tr1::unordered_set<std::string> words;
words.insert("removeme");
words.insert("removeme1");
stripWords(in_tokens,words);

3 个答案:

答案 0 :(得分:6)

您需要erase的双参数形式。不要超越自己并在不同的路线上写下来:

auto it = std::remove_if(input.begin(), input.end(), 
                         [&toRemove](std::string x) -> bool
                         { return toRemove.find(x) != toRemove.end(); });

input.erase(it, input.end());  // erases an entire range

答案 1 :(得分:3)

使用std::remove_if()的方法几乎是正确的方法,但它只删除了一个元素。您需要使用erase()的两个参数版本:

 input.erase(
     remove_if(input.begin(), input.end(), 
                 [&toRemove](std::string x) -> bool {
                     return toRemove.find(x) != toRemove.end();
                 }), input.end());

std::remove_if()重新排序元素,使得保留的元素位于序列的前面。它将迭代器it返回到第一个位置,该位置将被视为序列的新结尾,即,您需要删除范围[it, input.end())

答案 2 :(得分:1)

你已经得到了关于如何正确解决这个问题的几个答案。

现在,问题是你是否可以提高效率。答案取决于另一个问题:你关心向量中字符串的顺序吗?

如果您可以重新排列向量中的字符串而不会出现问题,那么您可以使删除效率大大提高。

不是从矢量中间移除字符串(需要移动所有其他字符串以填充孔),而是可以将所有不需要的字符串交换到矢量的末尾,然后将其删除。

特别是如果你只是从大型矢量的开头附近删除一些字符串,这可以提高 lot 的效率。例如,假设您要删除的字符串后跟1000个其他字符串。有了这个,你最终只交换两个字符串,然后擦除最后一个字符串(这很快)。使用当前的方法,最终只移动1000个字符串以删除一个。

更好的是,即使使用相当旧的编译器,您也可以预期交换字符串通常会非常快 - 通常比移动字符串更快(除非您的编译器足够新以支持移动分配)。