2010-09-03 6 views
7

Hat die C++ - Standardbibliothek und/oder Boost etwas Ähnliches wie die filter-Funktion in funktionalen Sprachen?"Filter" Funktion höherer Ordnung in C++

Die nächste Funktion, die ich finden konnte, war std::remove_copy_if, aber es scheint das Gegenteil von dem zu tun, was ich will. Hat boost::lambda irgendeine Funktion, um eine negierte Version meines Prädikats zu bekommen (ähnlich not in Haskell)? Ich könnte mein Prädikat negieren und es dann mit std::remove_copy_if verwenden.

Bitte beachten Sie, dass ich nicht frage, wie man filter Funktion in C++ schreibt; Ich frage nur, ob die Standardbibliothek und/oder Boost bereits eine solche Funktion bereitstellen.

Vielen Dank im Voraus.

+0

Wie ist 'std :: remove_copy_if()' Gegenteil von dem, was Sie wollen? Was ist das Gegenteil des Gegenteils? Wenn Sie nur Elemente an Ort und Stelle entfernen möchten, verwenden Sie Entfernen/Löschen idiom: 'container.rese (std :: entfernen_if (container.begin(), container.end(), pred()), container.end()); ' – wilx

+0

@wilx: Ich möchte, dass die Elemente, die das Prädikat erfüllen, beibehalten und andere entfernt werden. – missingfaktor

Antwort

6

<functional> Fügen Sie für std::not1 und versuchen cont.erase (std::remove_if (cont.begin(), cont.end(), std::not1 (pred())), cont.end());

+0

Genau das, was ich wollte. Vielen Dank! :-) – missingfaktor

+0

Aah, warte. Ich möchte nicht, dass die ursprüngliche Sammlung mutiert wird. Ich möchte eine neue modifizierte Kopie. – missingfaktor

+1

@Missing Faktor: Dann wollen Sie 'remove_copy_if' anstelle von' remove_if'. –

6

Es gibt ein Äquivalent zum Filtern in Boost.Range.
Hier ist ein Beispiel:

#include <vector> 
#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, 45, 3, 7, 66}; 
    std::vector<int> v2; 
    int dist = 5; 

    boost::push_back(v2, filter(v, _1 > dist)); 
    return 0; 
} 
+0

+1, Dies ist auch eine nette Lösung. – missingfaktor

1

ich viel funktionaler Stil Aufgaben finden können durch die Kombination boost.iterators gelöst werden. Dafür hat es filter_iterator.

Sag mal, haben Sie einen Vektor der natürlichen Zahlen, und eine Funktion, die Sie mit einem Paar von Iteratoren anwenden möchten, die nur das gefilterte Vektor sehen sollte, nur mit den ungeraden Zahlen:

#include <algorithm> 
#include <vector> 
#include <iterator> 
#include <numeric> 
#include <iostream> 
#include <boost/iterator/filter_iterator.hpp> 
template<typename Iter> 
void do_stuff(Iter beg, Iter end) 
{ 
    typedef typename std::iterator_traits<Iter>::value_type value_t; 
    copy(beg, end, std::ostream_iterator<value_t>(std::cout, " ")); 
    std::cout << '\n'; 
} 
struct is_even { 
     bool operator()(unsigned int i) const { return i%2 == 0; } 
}; 
int main() 
{ 
     std::vector<unsigned int> v(10, 1); 
     std::partial_sum(v.begin(), v.end(), v.begin()); // poor man's std::iota() 

     // this will print all 10 numbers 
     do_stuff(v.begin(), v.end()); 
     // this will print just the evens 
     do_stuff(boost::make_filter_iterator<is_even>(v.begin(), v.end()), 
       boost::make_filter_iterator<is_even>(v.end(), v.end())); 

} 
1

Verwenden remove_if oder remove_copy_if, mit not1 (definiert in <functional>), um das Prädikat zu invertieren. Etwas wie dieses:

#include <algorithm> 
#include <functional> 

template <class ForwardIterator, class Predicate> 
ForwardIterator filter(ForwardIterator first, ForwardIterator last, 
         Predicate pred) 
{ 
    return std::remove_if(first, last, std::not1(pred)); 
} 

template <class InputIterator, class OutputIterator, class Predicate> 
OutputIterator filter_copy(InputIterator first, InputIterator last, 
          OutputIterator result, Predicate pred) 
{ 
    return std::remove_copy_if(first, last, result, std::not1(pred)); 
}