[STL] Elemente aus vector entfernen mittels remove_if



  • Hallo.

    Ich habe etwa folgende Struktur:

    class Data
    {
       public:
           // foo
       private:
           int data;
    };
    
    [...]
    
    vector< Data > myVector;
    

    Nun moechte ich alle Elemente aus 'myVector' entfernen, bei denen das Objektattribut 'data' einen bestimmten (zur Laufzeit abzufragenden) Wert hat und dabei natuerlich gerne die Moeglichkeiten der STL nutzen. Bis hier kam ich:

    vector< Data >::iterator it;
    it = remove_if(myVector.begin(), 
                   myVector.end(),
                   ...);
    
    vector< Data > newVector(myVector.begin(), it); // Kopieren in neuen vector
    

    Wie man sieht, fehlt mir nun noch das wichtigste, naemlich das entsprechende Praedikat. Bei Suchen fand ich leider immer nur Beispiele fuer einstellige Praedikate, nicht aber mehrstellige ... daraus habe ich mir das folgende abgeleitet, was aber noch nicht wirklich funktioniert:

    struct MyTest
    {
        bool operator() (Data& d, value) const
        {
            return value == d.getData();
        }
    };
    

    Kann man das so ueberhaupt machen oder gibt es elegantere Wege?
    Danke!



  • Ein equal_to-Prädikat gibt es bereits, da musst du kein eigenes mehr Schreiben. Es reicht den op== für int zu überladen. Damit du den Wert bestimmen kannst musst du ihn an das Prädikat binden (in dem Fall an den zweiten Parameter von equal_to):

    #include <functional>
    
    remove_if(vec.begin(),vec.end(),bind2nd(equal_to<int>(),value));
    

    Wenn du keinen op== für int schreiben willst bleibt dir tatsächlich ein eigenes Prädikat nicht erspart:

    struct my_equal_to : public binary_function<Data,int,bool>
    {
        // ob hier wirklich const int& sein muss, weiß ich nicht...
        bool operator () (const Data& data, const int& value) const
        {
            return data.getData() == value;
        }
    }
    
    remove_if(vec.begin(),vec.end(),bind2nd(my_equal_to(),value));
    

    Das Programmieren mit der STL bereitet mir jedes Mal Schmerzen 😮

    MfG SideWinder



  • Wenn du alle Werte entfernen willst die gleich einen anderen Wert sind dann benutz remove oder remove_copy.

    Wenn der origninal Vector verändert werden soll.

    vector<int>vec;
    vec.erase(remove(vec.begin(), vec.end(), 8), vec.end());
    

    Wenn eine Kopie erstellt werden soll.

    vector<int>in;
    vector<int>out;
    remove_copy(in.begin(), in.end(), back_inserter(out), 8);
    

    Wenn es jetzt mehr als nur ein Test auf Gleichheit ist, dann musst du dir entweder selbst ein Prädikat schreiben oder lambda Ausdrücke benutzen.

    struct MyFunc
    {
      MyFunc(int value):value(value){}
      bool operator()(const Data&data)const{
        return data.foo() == value;
      }
      int value;
    }
    //...
    vector<Data>vec;
    vec.erase(remove_if(vec.begin(), vec.end(), MyFunc(8)), vec.end());
    //...
    vector<Data>in;
    vector<Data>out;
    remove_copy_if(in.begin(), in.end(), back_inserter(out), MyFunc(8));
    

    Um lambda Ausdrücke zu benutzen brauchst du boost::lambda. Da das ganze mit Templates gemacht wird kann es die Übersetzungszeit ganz schön vergrößern. Hoffen wir mal, dass der neue C++ Standard diesbezüglich Abhilfe schafft.

    vector<Data>vec;
    vec.erase(remove_if(vec.begin(), vec.end(), 8 == _1.foo()), vec.end());
    


  • Ist es nicht:

    vec.erase(std::remove_if(vec.begin(), vec.end(), std::bind2nd(std::greater<int>,val)), vec.end());
    

    Dachte, das man es mit greater bindet...

    Ghost


Anmelden zum Antworten