Adapting Map Iterators Using STL / Boost / Lambdas

Consider the following non-working code:

typedef map<int, unsigned> mymap; mymap m; for( int i = 1; i < 5; ++i ) m[i] = i; // 'remove' all elements from map where .second < 3 remove_if(m.begin(), m.end(), bind2nd(less<int>(), 3)); 

I am trying to remove items from this map where .second < 3 . This is clearly not spelled correctly. How to write it correctly using:

  • Standard functions and methods of the STL function using bind + less<> , but without the need to write a custom functor
  • Boost.Bind
  • C ++ 0x Lambdas

I know that I do not erase elements. Do not worry about it; I am just simplifying the problem to solve.

+4
source share
3 answers

I'm not sure how to do this using only STL bindings, but I think your main problem is that what is passed to the functor that you pass remove is not just int , but << 22>.

Using boost :: bind, you would do it like this:

 remove_if(m.begin(), m.end(), bind(&std::pair<int, unsigned>::second, _1) < 3); 

Using a lambda function, itโ€™s something like this:

 remove_if(m.begin(), m.end(), [](const std::pair<int, unsigned>& p) { return p.second < 3; } ); 

I did not check that this compiles, sorry.

+3
source

remove_if will not work with associative containers. But remove_copy_if may work, but by copying your card. Instead, I will do it with count_if .

1) Standard functions and methods of the STL function using bind + less <> but without the need to write a custom functor

 // I don't think it can be done with standard c++ without introducing new functors and adaptors. std::size_t count = std::count_if( m.begin(), m.end(), std::sgi::compose1( std::bind_2nd( std::less<int>(), 3 ), &boost::get<1,mymap::value_type> ) ); 

2) Boost.Bind

 std::size_t count = std::count_if( m.begin(), m.end(), boost::compose_f_gx( &boost::bind( std::less<int>, _1, 3 ) &boost::get<1,mymap::value_type> ) ); 

3) C ++ 0x Lambdas

 std::size_t count = std::count_if( m.begin(), m.end(), []( const mymap::value_type& item ) { return item.second < 3; } ); 

If you really need remove_if behavior, you need to collapse your own algorithm. I do not believe that there are modifying standard algorithms that work with associative containers.

 template< typename FwdIter, typename AssocCont, typename Pred > std::size_t assoc_remove_if( FwdIter iter, FwdIter end, AssocCont& cont, Pred pred ) { std::size_t count = 0; while( iter != end ) { if( pred(*iter) ) { ++count; iter = cont.erase(iter); } else { ++iter; } } return count; } 
+2
source

Although I couldnโ€™t get the remove_if algorithm remove_if work for the reasons mentioned above, I got the count_if algorithm to work with somewhat complex functor definitions and compositions. They are not defined in the standard, but they are inspired by what is available in the SGI STL .

 template <class Pair> struct select2nd : std::unary_function<Pair, typename Pair::second_type> { typedef std::unary_function<Pair, typename Pair::second_type> super; typedef typename super::result_type result_type; typedef typename super::argument_type argument_type; result_type & operator ()(argument_type & p) const { return p.second; } result_type const & operator ()(argument_type const & p) const { return p.second; } }; template <class UnaryFunc1, class UnaryFunc2> struct unary_compose : std::unary_function<typename UnaryFunc2::argument_type, typename UnaryFunc1::result_type> { typedef std::unary_function<typename UnaryFunc2::argument_type, typename UnaryFunc1::result_type> super; typedef typename super::result_type result_type; typedef typename super::argument_type argument_type; UnaryFunc1 func1_; UnaryFunc2 func2_; unary_compose(UnaryFunc1 f1, UnaryFunc2 f2) : func1_(f1), func2_(f2) {} result_type operator () (argument_type arg) { return func1_(func2_(arg)); } }; template <class UnaryFunc1, class UnaryFunc2> unary_compose<UnaryFunc1, UnaryFunc2> compose1(UnaryFunc1 f1, UnaryFunc2 f2) { return unary_compose<UnaryFunc1, UnaryFunc2>(f1,f2); }; int main(void) { typedef std::map<int, unsigned> mymap; mymap m; for(int i = 0; i < 5; ++i ) m[i] = i; std::cout << "Count = " << std::count_if(m.begin(), m.end(), compose1(std::bind2nd(std::less<int>(), 3), select2nd<mymap::value_type>())) << std::endl; } 
+1
source

Source: https://habr.com/ru/post/1308072/


All Articles