如何为vector<string>实现remove_if_not功能?
问题描述
我想实现类似下面代码的功能:
v.erase(remove_if(v.begin(), v.end(), !pointer_to_func), v.end());
其中v是std::vector<std::string>类型,pointer_to_func是如下函数指针:
bool (*pointer_to_func)(std::string);
我知道!pointer_to_func写法错误,但这是我想要的核心逻辑——保留满足pointer_to_func条件的元素,移除不满足的。
该功能在类中的声明如下:
void Place::filter_ss(bool (*n)(std::string)){}; // 函数指针标注为FP
我试过多种方法,但not1、not2、ptr_fun这些方法已经被废弃/移除了。函数在main中的调用方式如下:
int main(){ // 所有元素push_back到vector v中 Place p{"Observatory", "Airport", "Delicatessen", "Theater", "Vacation"}; // 这个函数是难点,它接收字符串直接删除不包含指定子串的单词 p.filter_ss(at); // 循环应该输出: Observatory Delicatessen Theater Vacation for (size_t x = 0; x < p.v.size(); x++) cout << p.v[x] << " "; ... // 其他操作 ... // 更多操作 return 0; }
注:原代码中Place p(){"..."}是语法错误,修正为Place p{"..."};循环条件的逗号需改为分号,cout需输出p.v[x]而非v[x]。
我的代码只有用预定义测试函数时能正常工作,比如:
bool st(string str){ return str.find("st") < string::npos; }
我尝试了几种实现方式,但都达不到预期效果,求正确实现方案或方向指导。
尝试的实现思路
- 临时容器拷贝法
void Place::filter_ss(bool (*n)(string)){ pointer_to_func = n; vector<string> temp; for(size_t t = 0; t < v.size(); t++){ if(pointer_to_func(v[t])){ temp.push_back(v[t]); } } v.clear(); for(auto s : temp) v.push_back(s); }
- 结合erase-remove_if和废弃的not1/ptr_fun
void Place::filter_ss(bool (*n)(string)){ pointer_to_func = n; v.erase(remove_if(v.begin(), v.end(), not1(ptr_fun(pointer_to_func))), v.end()); }
- copy_if用法(逻辑错误)
void Place::filter_ss(bool (*n)(string)){ vector<string> temp; pointer_to_func = n; copy_if(temp.begin(), temp.end(), back_inserter(v), pointer_to_func); }
正确实现方案
由于C11及以后not1/ptr_fun已被废弃,推荐使用lambda表达式反转判断逻辑,这是最简洁且符合现代C规范的方式。
方案1:lambda配合erase-remove_if(最优)
void Place::filter_ss(bool (*pred)(std::string)) { // 用lambda反转判断条件:移除不满足原条件的元素 v.erase( std::remove_if(v.begin(), v.end(), [pred](const std::string& s) { return !pred(s); } ), v.end() ); }
remove_if会移除所有返回true的元素,lambda返回!pred(s),刚好把不满足原条件的元素标记为待移除,最终通过erase完成删除。无需额外容器,效率最高。
方案2:修复临时容器拷贝法(兼容旧标准)
如果环境不支持C++11,可优化第一种尝试的代码:
void Place::filter_ss(bool (*pred)(std::string)) { std::vector<std::string> temp; temp.reserve(v.size()); // 预分配空间提升效率 for (const auto& s : v) { // 范围for循环更简洁 if (pred(s)) { temp.push_back(s); } } v.swap(temp); // 用swap代替clear+push_back,避免内存重新分配 }
方案3:修正copy_if逻辑
第三种尝试的源容器和目标容器搞反了,正确写法如下:
void Place::filter_ss(bool (*pred)(std::string)) { std::vector<std::string> temp; temp.reserve(v.size()); std::copy_if(v.begin(), v.end(), std::back_inserter(temp), pred); v.swap(temp); }
copy_if会把原容器v中满足条件的元素拷贝到temp,最后用swap替换原容器。
之前代码失败的原因
- 尝试2使用了已废弃的
not1/ptr_fun,C++17中已完全移除,编译器会报错; - 尝试3中
copy_if的源容器是空的temp,目标是原容器v,逻辑完全错误; main中的代码存在语法错误,导致对象初始化或输出逻辑异常。
内容的提问来源于stack exchange,提问作者that_one_guy
相关产品推荐
相关产品推荐

