使用erase和remove-if:传递多个参数给函数



我想迭代和擦除std::vector中的项,但我希望将每个项与vector中的前一项和下一项进行比较,并执行一些计算。如果满足某个条件,项目将被擦除。是否有可能传递多个参数,迭代器为前,当前和下一个向量项,函数remove-if接收?如果没有,我如何访问传递给remove-if的函数中的上一个和下一个迭代器项?

  1. 正如在评论中指出的那样,您需要一个中间容器来存储必须删除的元素,因为如果前一个元素已被删除,则不能用于检查下一个元素是否必须被删除。
  2. 上一个和下一个可能会掉出容器。谓词函数(也称为test或check)可以接受指针而不是引用,这样nullptr就可以通知容器外的元素。实现:

template<class _FwdIt, class _Pr>
inline _FwdIt remove_if_with_prev_and_next(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{
if (_First == _Last) {
return _First;
}
auto first = _First;
auto next = std::next(first);
std::vector<char> remove; // vector<bool> is bad:-(
remove.push_back(_Pred(nullptr, *first, next == _Last ? nullptr : &*next) ? 1 : 0);
while (next != _Last) {
auto prev = first;
first = next;
++next;
remove.push_back(_Pred(&*prev, *first, next == _Last ? nullptr : &*next) ? 1 : 0);
}
auto remove_it = remove.begin();
// assume remove_if calls the predicate only once for every element, in order
return std::remove_if(_First, _Last, [&remove_it](const auto&) { return *remove_it++ > 0; });
}
int main()
{
std::vector<int> v{ 1, 1, 2, 3, 3, 4, 5, 3, 5, 5, 5, 5, 4, 3, 3 };
std::list<int> l{ 1, 1, 2, 3, 3, 4, 5, 3, 5, 5, 5, 5, 4, 3, 3 };
auto equal_to_prev_or_next = [](const int* prev, int el, const int* next) { return (prev && *prev == el) || (next && *next == el); };
v.erase(remove_if_with_prev_and_next(v.begin(), v.end(), equal_to_prev_or_next), v.end());
l.erase(remove_if_with_prev_and_next(l.begin(), l.end(), equal_to_prev_or_next), l.end());
}

不是将所有检查都存储在vector中,测试一个元素可以首先预先计算是否应该删除下一个元素。实现:

template<class _FwdIt, class _Pr>
inline _FwdIt remove_if_with_prev_and_next_2(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{
if (_First == _Last) {
return _First;
}
auto first = _First;
auto next = std::next(first);
bool remove = _Pred(nullptr, *first, next == _Last ? nullptr : &*next);
auto get_remove_this_and_test_next = [&remove, &first, &next, &_Last, &_Pred](const auto&) {
bool remove_this = remove;
if (next != _Last) {
auto prev = first;
first = next;
++next;
remove = _Pred(&*prev, *first, next == _Last ? nullptr : &*next);
}
return remove_this;
};
// assume remove_if calls the predicate only once for every element, in order :-(
return std::remove_if(_First, _Last, get_remove_this_and_test_next);
}
int main()
{
std::vector<int> v{ 1, 1, 2, 3, 3, 4, 5, 3, 5, 5, 5, 5, 4, 3, 3 };
std::list<int> l{ 1, 1, 2, 3, 3, 4, 5, 3, 5, 5, 5, 5, 4, 3, 3 };
auto equal_to_prev_or_next = [](const int* prev, int el, const int* next) { return (prev && *prev == el) || (next && *next == el); };
v.erase(remove_if_with_prev_and_next_2(v.begin(), v.end(), equal_to_prev_or_next), v.end());
l.erase(remove_if_with_prev_and_next_2(l.begin(), l.end(), equal_to_prev_or_next), l.end());
}

两种实现都假设remove_if对每个元素只按顺序调用谓词一次。这是合理的假设,但不能保证。如果你想100%确定它能工作,用这个可能的实现(第二版)替换对remove_if的调用。

相关内容

  • 没有找到相关文章

最新更新