tags:

views:

172

answers:

5

Hi, I have a vector of points, and I need to get those which are at a distance less than a value from a given point.

I could do it with a simple loop, but is there a better way to do it?

Thanks in advance

+10  A: 

Use std::remove_copy_if:

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

int main() {
    std::vector<int> v;
    v.push_back(3);
    v.push_back(2);
    v.push_back(6);
    v.push_back(10);
    v.push_back(5);
    v.push_back(2);
    std::vector<int> v2;

    std::remove_copy_if(v.begin(), v.end(), back_inserter(v2),
            std::bind2nd(std::greater<int>(),5));

    std::copy (v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout));
    std::cout << std::endl;
    return 0;
}

remove_copy_if will copy a sequence to an output iterator for each item which fails a predicate. In this case, the predicate is "x>5". There doesn't seem to be an equivalent copy_if for each item which passes a predicate test, but you can always negate a predicate with std::not1.

Philip Potter
You should probably mention how to write a predicate for comparing distances in higher dimensions.
Beta
@Beta: my C++ is a bit rusty for that, but if you want to write an example I'll community wiki this answer and you can add it in.
Philip Potter
+3  A: 

as Philip and Beta suggest, here is a more general way, using a functor predicate. you could use C++0x lambdas instead of a handwriten functor.

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

struct FunctorPredicate : public std::unary_function<bool,int>
{
   bool operator(int i)
   (
      // do what you want here, in our case: test greater than 5.
      return i > 5; 
   )
}

int main() {
    std::vector<int> v;
    v.push_back(3);
    v.push_back(2);
    v.push_back(6);
    v.push_back(10);
    v.push_back(5);
    v.push_back(2);
    std::vector<int> v2;

    FunctorPredicate functorPredicate;
    std::remove_copy_if(v.begin(), v.end(), back_inserter(v2),functorPredicate);

    std::copy (v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout));
    std::cout << std::endl;
    return 0;
}

inheriting form std::unary_function defines the two following typedef: argument_type at int and result_type at bool.

and in Cplusplus STL reference for std::remove_copy_if there is another example with a simpler std::function<bool (int)>.

Stephane Rolland
@Stephen Rolland: Can we also use std::partition?
Chubsdad
It's good practice to make your predicate inherit from `std::unary_function`.
Philip Potter
@Philip Potter, you are right, it defines the STL type traits for this function... but I still haven't started to you use them in practice. I really should, and thank you for the remark.
Stephane Rolland
@chubsdad, yes you can also use it with partition, look at this example: http://www.cplusplus.com/reference/algorithm/partition/
Stephane Rolland
one other advantage of `std::unary_function` that you don't mention is that it lets you use `std::not1` to negate it.
Philip Potter
@Philip, I neither have used std:notl yet. Thanx for the tip.
Stephane Rolland
that's a one (1) not an ell (l). It means "negate a predicate which takes 1 argument".
Philip Potter
In C++0x, not only will you have lambdas, you'll also get a `copy_if` algorithm, which was apparently left out of the stdlib by oversight.
UncleBens
@uncleBens I don't understand, what this `copy_if` would bring more ?
Stephane Rolland
Just that you wouldn't have to think about all the negations with `remove_copy_if` and can do a rather common operation in a straightforward way.
UncleBens
@uncle okay I understand, I'm gonna correct my answer with your proposal which I feel can be better
Stephane Rolland
A: 

Maxim proposed the boost::filter_iterator already, but I suggest going one step further. The boost iterators alone are very cumbersome to use. Typically, you want to filter ranges, copy ranges, or search ranges. For every boost iterator, we have a utility function make_xxx_range like the following:

#include <boost/iterator/filter_iterator.hpp>
#include <boost/range/iterator_range.hpp>

template< class Range, class Pred >
boost::iterator_range< boost::filter_iterator< Pred, typename boost::range_iterator<Range>::type > > 
make_filter_range( Range& rng, Pred p ) {
    return boost::make_iterator_range( boost::make_filter_iterator(pred, boost::begin(rng), boost::end(rng)), boost::make_filter_iterator(pred, boost::end(rng), boost::end(rng)) );
}

Having that, the solution to your problem is trivial:

#include <boost/lambda/lambda.hpp> 
int main() {
    std::vector<int> v;
    // fill vector
    std::vector<int> v2 = boost::copy_range< std::vector<int> >( 
        make_filter_range( v, boost::lambda::_1 > 5 );
}
Sebastian
A: 

Sebastian proposed the boost::make_xxx_range functions already, but I suggest going one step further. The boost::make_xxx_range alone are very cumbersome to use. Typically, you want to use boost::range ;)

#include <vector>
#include <iostream>
#include <boost/lambda/lambda.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
#include <boost/range/adaptor/filtered.hpp>

using namespace boost::adaptors;
using namespace boost::lambda;

int main()
{
    std::vector<int> v = {3, 2, 6, 10, 5, 2};
    std::vector<int> v2;
    int dist = 5;

    boost::push_back(v2, filter(v, _1 > dist));

    boost::copy(v2, std::ostream_iterator<int>(std::cout, ","));
    std::cout << std::endl;
    return 0;
}
Thomas Petit