set_intersection /difference bei maps/sets



  • Hallo zusammen,

    ich hab eine Frage. Wie kann ich die methoden set_intersection bzw. set_difference bei sets/maps ausführen ?

    Mein Ansatz ist:

    map<string,int> myMap1, myMap2, myMap3;
    
    //füllen von myMap1 & myMap2
    
    set_intersection(myMap1.begin(),myMap1.end(),myMap2.begin(),myMap2.end(), myMap3.begin());
    

    erhalte aber immer eine Fehlermeldung 😞



  • ist ja interessant 'set_intersection' auf map's anzuwenden 🕶

    Deine Fehlermeldung ist die des Compilers, der besagt, dass er einem pair< const string, int > nichts zuwesien kann. Was ok ist, da der Iterator einer map kein Output-Iterator ist.
    Als 5. Parameter von 'set_intersection' wird aber ein Output-Iterator verlangt.

    Versuch' mal

    #include <iterator>     // inserter
        // ...
        set_intersection( myMap1.begin(), myMap1.end(), myMap2.begin(), myMap2.end(), 
            inserter( myMap3, myMap3.end() ) );
    

    Gruß
    Werner



  • Jetzt funktionierts 🙂
    Ist es auch möglich bei set_difference nur zu vergleichen ob die Keys übereinstimmen ?
    Bis jetzt werden die Elemente nur in myMap3 geschrieben, wenn sowohl die Keys und values übereinstimmen.
    Das heisst wenn in mymap1 ["der",1] steht und in mymap2["der",4] so ist "der" nicht in der Schnittmenge vorhanden, was ich aber gerne hätte.
    Ist es möglich dass mit der Standardfunktion set_intersection zu erreichen ?



  • Ja, du kannst als zusätzlichen Parameter myMap1.value_comp() an die Funktion übergeben - das ist das Prädikat, mit dem die Elemente innerhalb der Map verglichen werden.



  • Also, ich hab schon etwas damit rumprobiert und es funktioniert auch "teilweise".
    Was nicht funktioniert ist folgendes.
    Ich habe zwei map<double,string> -Strukturen, die ich auf Gemeinsamkeiten (im string-Feld untersuchen will.

    Der Code den ich dafür verwende ist:

    set_intersection(myMap1.begin(),myMap1.end(),myMap2.begin(),myMap2.end(),inserter(myMap3,myMap3.end()),myMap1.key_comp());
    

    mit diesem Code erhalte ich immer einen Fehler beim Compilieren.

    Wenn ich stattdessen myMap1.value_comp() verwende, erhalte ich keinen Fehler beim Compilieren:

    set_intersection(myMap1.begin(),myMap1.end(),myMap2.begin(),myMap2.end(),inserter(myMap3,myMap3.end()),myMap1.value_comp());
    

    Aber damit erhalte ich natürlich nicht das gewünschte Ergebnis 😞



  • Laser schrieb:

    mit diesem Code erhalte ich immer einen Fehler beim Compilieren.

    Welchen Fehler?

    PS: map's sind nur bezüglich des Schlüssels sortiert (bei deinem Beispiel also das double-Feld), aber nicht bezüglich des zugeordneten Wertes - also kannst du set_intersection auch nicht auf den Wert-Teil der map anwenden (jedenfalls nicht direkt).



  • mein code sieht ungefähr so aus:

    map<double,string> myMap1, myMap2; 
    set<string> entries;
    
     //füllen von myMap1 & myMap2 
    
    set_intersection( myMap1.begin(), myMap1.end(), myMap2.begin(), myMap2.end(), 
             inserter( entries, entries.end() ),myMap1.key_comp() );
    

    und die fehlermeldung so:

    g++ -O0 -g3 -Wall -c -fmessage-length=0 -oMainMenu.o ../MainMenu.cpp
    /usr/include/c++/4.0.2/bits/stl_algo.h: In function ‘_OutputIterator std::set_intersection(_InputIterator1, _InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator, _Compare) [with _InputIterator1 = std::_Rb_tree_iterator<std::pair<const double, std::string> >, _InputIterator2 = std::_Rb_tree_iterator<std::pair<const double, std::string> >, _OutputIterator = std::insert_iterator<std::set<std::string, std::less<std::string>, std::allocator<std::string> > >, _Compare = std::less<double>]’:
    ../MainMenu.cpp:367:   instantiated from here
    /usr/include/c++/4.0.2/bits/stl_algo.h:4281: error: no match for call to ‘(std::less<double>) (std::pair<const double, std::string>&, std::pair<const double, std::string>&)’
    /usr/include/c++/4.0.2/bits/stl_function.h:226: note: candidates are: bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = double]
    ../MainMenu.cpp:367:   instantiated from here
    /usr/include/c++/4.0.2/bits/stl_algo.h:4283: error: no match for call to ‘(std::less<double>) (std::pair<const double, std::string>&, std::pair<const double, std::string>&)’
    /usr/include/c++/4.0.2/bits/stl_function.h:226: note: candidates are: bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = double]
    ../MainMenu.cpp:367:   instantiated from here
    /usr/include/c++/4.0.2/bits/stl_algo.h:4287: error: no match for ‘operator=’ in ‘__result. std::insert_iterator<_Container>::operator* [with _Container = std::set<std::string, std::less<std::string>, std::allocator<std::string> >]() = __first1. std::_Rb_tree_iterator<_Tp>::operator* [with _Tp = std::pair<const double, std::string>]()’
    /usr/include/c++/4.0.2/bits/stl_iterator.h:531: note: candidates are: std::insert_iterator<_Container>& std::insert_iterator<_Container>::operator=(typename _Container::const_reference) [with _Container = std::set<std::string, std::less<std::string>, std::allocator<std::string> >]
    /usr/include/c++/4.0.2/bits/stl_iterator.h:491: note:                 std::insert_iterator<std::set<std::string, std::less<std::string>, std::allocator<std::string> > >& std::insert_iterator<std::set<std::string, std::less<std::string>, std::allocator<std::string> > >::operator=(const std::insert_iterator<std::set<std::string, std::less<std::string>, std::allocator<std::string> > >&)
    

    Die Sache ist dass die Map schon nach den double-Werten sortiert sein soll weil die eine Art "Bewertung" darstellen, aber andererseits will ich gucken ob es "Einträge/Strings" gibt die in beiden Maps vorkommen (dürfen sich in den Bewertungen unterscheiden)

    Könnte ja auch eine eigene set_intersection-Methode implementieren, bei der ich selber mit Iteratoren überprüfe wo die Elemente gleich sind, aber dachte dass es auch mit der STL-Methode gehen muss/sollte (die wohl effizienter ist)



  • Ups, stimmt - map::key_comp() erwartet Schlüsselwerte (in deinem Fall double's), die es vergleichen soll.

    Und ja: set_intersection ist effizienter als ein linearer Vergleich, ABER es erwartet, daß der Suchbereich entsprechend dem gesuchten Kriterium sortiert ist (und eine map<double,string> ist NICHT nach den string's sortiert). Du könntest höchstens einen Umweg über einen zweiten Container verwenden:

    template<typename F,typename S>
    bool cmp2nd(const pair<F,S>& lhs,const pair<F,S>& rhs)
    { return lhs.second<rhs.second; }
    
    map<double,string> map1,map2;
    multimap<double,string> target;
    
    //umkopieren in Vectoren:
    vector<pair<double,string> data1(map1.begin(),map1.end()),data2(map2.begin(),map2.end());
    //diese Vectoren kannst du jetzt nach deinen eigenen Vorstellungen sortieren und mergen:
    sort(data1.begin(),data1.end(),cmp2nd);
    sort(data2.begin(),data2.end(),cmp2nd);
    set_intersection(data1.begin(),data1.end(),data2.begin(),data2.end(),inserter(target,target.begin()),cmp2nd);
    

    (oder du nutzt transform(), um aus jeder map die string-Hälften rauszuziehen)


Anmelden zum Antworten