【问题标题】:Iterator range erase element迭代器范围擦除元素
【发布时间】:2014-06-11 01:30:01
【问题描述】:

是否可以从 iterator_range 中删除元素?

类似这样的东西(不幸的是这段代码不起作用):

void test_erase(my_it it,my_it end){
boost::iterator_range<my_it> r(it,end); 
for(; it<end; it++){
    if(pred(my_it)){
        boost::erase(r,boost::iterator_range<my_it>(it,it));
        continue;
    }
}

pred 检查 my_it 和 (my_it+1) 的值

关键是摆脱像vectormapstring这样的构造对象

【问题讨论】:

  • 为什么这里需要一个范围?因为你毕竟通过了开始和结束? void test_erase(my_it it,my_it end)
  • 我想这只是展示这个想法的一个最小例子。
  • 摆脱范围也很好。重点不在于构造像vectormapstring 这样的对象
  • 想法是将开始和结束迭代器传递给函数,然后根据谓词创建要删除的迭代器范围?为什么不用 remove_if 或简单迭代?
  • 因为 remove_if 谓词只接受迭代器的值 (*it),并且不允许检查邻居的值

标签: c++ algorithm boost stl iterator


【解决方案1】:

虽然 remove_if 对一元谓词进行操作,但将其扩展到任何其他 n 参数谓词并不困难。

例如 remove with binary predicate 可以这样写:

template<class ForwardIt, class BinaryPredicate>
ForwardIt removeif(ForwardIt first, ForwardIt last, BinaryPredicate p) {

    ForwardIt result = first;
    while ( first != last - 1) {
        if ( !p( *first, *( first + 1))) {
            *result = *first;
            ++result;
        }
        if( first == last - 1) return result;
        ++first;
    }
    return result;
}

但是您必须根据自己的需要来调整它。这完全取决于您如何处理成对的元素,如果谓词返回 true 或其中一个,您是否要删除它们?只有左边还是只有右边?等等……

用法:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

bool bp (int left, int right) { return ( left + right == 2); }
/*
 * 
 */
int main(int argc, char** argv) {

    int a[] = { 0, 2, 1, 3, 0, 2, 3, 2, 0, 3, 8};
    std::vector<int> v( a, a + 11);
    std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, ","));
    std::cout << std::endl;
    std::vector<int>::iterator it = removeif( v.begin(), v.end(), bp);
    std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, ","));
    v.erase( it, v.end()); std::cout << std::endl;
    std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, ","));
    return 0;
}

输出:

0,2,1,3,0,2,3,2,0,3,8,

2,1,3,2,3,0,3,2,0,3,8,

2,1,3,2,3,0,3,

http://ideone.com/8BcmJq


如果条件成立,此版本会删除这两个元素。

template<class ForwardIt, class BinaryPredicate>
ForwardIt removeif(ForwardIt first, ForwardIt last, BinaryPredicate p) {

    ForwardIt result = first;
    while (first != last - 1) {
        if (!p(*first, *(first + 1))) {
            *result++ = *first++;
            *result++ = *first++;
        } else {
            if (first == last - 1) return result;
            ++first;
            ++first;
        }
    }
    return result;
}

0,2,1,3,0,2,3,2,0,3,8,

1,3,3,2,0,3,3,2,0,3,8,

1,3,3,2,0,3,

【讨论】:

  • 非常感谢!我已经抓住了这个想法,现在我可以完成我的代码了
【解决方案2】:

迭代器范围只不过是一对底层迭代器。

因此,是否可以在不使对中的迭代器无效的情况下从底层容器中擦除,取决于底层容器。

一般来说,std::list 会支持这一点,但不是例如std::vector

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多