문제

Is it possible to erase elements from iterator_range?

Something like this (unfortunately this code does not work):

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 checks value of my_it and of (my_it+1)

The point is get rid of constructing objects like vector, map or string

도움이 되었습니까?

해결책

Although remove_if operates on unary predicate it is not difficult to extend it on any other n arguments predicate.

For example remove with binary predicate can be written this way:

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;
}

But you have to fit this to your needs. It all depends how you treat pairs of elements, do you want to remove both of them if predicate returns true or one of them? Only left or only right? etc...

usage:

#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;
}

output:

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


This version removes both elements if condition holds.

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,

다른 팁

Iterator range is nothing more than a pair of underlying iterators.

So whether or not you can erase from the underlying container without invalidating the iterators in your pair, depends on the underlying container.

In general, std::list would support this, but not e.g. std::vector

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top