Как заполнить std :: vector данными из другого вектора, который соответствует некоторым критериям - PullRequest
4 голосов
/ 27 августа 2010

У меня есть вектор точек, и мне нужно получить те, которые находятся на расстоянии, меньшем, чем значение из данной точки.

Я мог бы сделать это с помощью простого цикла, но есть ли лучший способ сделать это?

Заранее спасибо

Ответы [ 5 ]

10 голосов
/ 27 августа 2010

Использование 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 скопирует последовательность в выходной итератор для каждого элемента, который не соответствует предикату. В этом случае предикатом является «x> 5». Кажется, что нет эквивалента copy_if для каждого элемента, который проходит тест на предикаты, но вы всегда можете отменить предикат с помощью std::not1.

4 голосов
/ 27 августа 2010

, как предлагают Филипп и Бета, вот более общий способ, использующий предикат функтора. Вы можете использовать лямбды C ++ 0x вместо рукописного функтора.

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

наследование формы std :: unary_function определяет два следующих typedef: тип аргумента в int и тип результата в bool.

и в Cplusplus STL для std :: remove_copy_if есть еще один пример с более простым std::function<bool (int)>.

4 голосов
/ 27 августа 2010
2 голосов
/ 28 августа 2010

Себастьян уже предложил функции boost::make_xxx_range, но я предлагаю пойти еще дальше. Boost :: make_xxx_range один очень громоздкий в использовании. Как правило, вы хотите использовать 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;
}
0 голосов
/ 27 августа 2010

Максим уже предложил boost::filter_iterator, но я предлагаю пойти еще дальше. Одни только буст-итераторы очень громоздки в использовании. Как правило, вы хотите фильтровать диапазоны, копировать диапазоны или диапазоны поиска. Для каждого повышающего итератора у нас есть служебная функция make_xxx_range, подобная следующей:

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

Имея это, решение вашей проблемы тривиально:

#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 );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...