Kopieren von Maps unterschiedlichen Typs



  • Hallo an alle,

    ich habe zwei maps unterschiedlichen Typs und würde nun gerne eine Map in die andere kopieren (zum. die Keys).

    typedef std::map<IMyClass*, bool> RegisteredMyClass;
      RegisteredMyClass m_mRegisteredMyClass;
    
      typedef std::map<IMyClass*, int> WaitingList;
      WaitingList m_mWaitingListMyClass;
    

    Die Elemente der WaitingList sollen in die RegisteredMyClass kopiert werden oder genauer etwas genauer die Keys und jeder bool sollte auf false gesetzt werden.

    Meine erster Ansatz ist nun dieser:

    void MyClass::Register()
        {
          WaitingList::const_iterator itCurrent(m_mWaitingListMyClass.begin());
          WaitingList::const_iterator itEnd(m_mWaitingListMyClass.end());
    
          for ( ; itCurrent != itEnd; ++itCurrent)
          {
            m_mRegisteredMyClass[itCurrent->first] = false;
          }
    
          m_mWaitingListMyClass.clear();
        }
    

    Gibt es einen schöneren und eleganteren Weg Keys zu kopieren mit der STL (copy, transform, ...)?

    Danke,
    Markus



  • Also für copy müsstest du dir wahrscheinlich einen eigenen Iterator schreiben, den du als dritten Parameter übergibst.
    Ich habs mit transform versucht, hab aber leider immer irgendwelche Compilerfehler bekommen.
    Hier wäre eine Variante mit for_each:

    #include <algorithm>
    #include <iterator>
    #include <map>
    #include <iostream>
    
    typedef std::map<int, bool> IntBool;
    typedef std::map<int, int> IntInt;
    
    class func
    {
        public:
            func(std::map<int, bool>& m) : ii(m) {}
            void operator() (const std::pair<int, int>& p) { ii.insert(std::make_pair(p.first, false)); }
        private:
            std::map<int, bool>& ii;
    };
    
    int main(int argc, char* argv[])
    {
        IntInt ii;
        IntBool ib;
    
        ii[0] = 0;
        ii[1] = 1;
        ii[2] = 2;
        ii[3] = 3;
    
        for(std::map<int, int>::iterator iter1 = ii.begin(); iter1 != ii.end(); ++iter1)
            std::cout << iter1->first << " " << iter1->second << std::endl;
    
        std::for_each(ii.begin(), ii.end(), func(ib));
    
        for(std::map<int, bool>::iterator iter2 = ib.begin(); iter2 != ib.end(); ++iter2)
            std::cout << iter2->first << " " << iter2->second << std::endl;
    }
    


  • Also ich habs jetzt doch noch mit transform hinbekommen. Ist ein bisschen kürzer weil eine freie Funktion reicht und du keinen Funktor schreiben musst.

    #include <algorithm>
    #include <iterator>
    #include <map>
    #include <iostream>
    
    typedef std::map<int, bool> IntBool;
    typedef std::map<int, int> IntInt;
    
    std::pair<int, bool> func(const std::pair<int, int>& p)
    {
        return std::make_pair(p.first, false);
    }
    
    int main(int argc, char* argv[])
    {
        IntInt ii;
        IntBool ib;
    
        ii[0] = 0;
        ii[1] = 1;
        ii[2] = 2;
        ii[3] = 3;
    
        for(std::map<int, int>::iterator iter1 = ii.begin(); iter1 != ii.end(); ++iter1)
            std::cout << iter1->first << " " << iter1->second << std::endl;
    
        std::transform(ii.begin(), ii.end(), std::inserter(ib, ib.end()), func);
    
        for(std::map<int, bool>::iterator iter2 = ib.begin(); iter2 != ib.end(); ++iter2)
            std::cout << iter2->first << " " << iter2->second << std::endl;
    }
    

  • Mod

    Es ist evtl. sinnvoll anzumerken, dass diese Lösung zwar einigermaßen elegant aber auch, zumindest wenn IntInt nicht zuvor leer ist, möglicherweise ineffizient ist.
    Wenn N die Anzahl der Elemente in IntBool, und M die Anzahl IntInt ist, können wir die Komplexität obigen Algorithmuses in erster Näherung als O(N*lg(M)) abschätzen. Das stimmt nicht so ganz, weil die Größe der Map ja während des Einfügens anwächst, aber damit erhöht sich die Komplexität ja nur noch weiter.
    Es ist aber andererseits sehr einfach, einen Algorithmus anzugeben mit O(N+M), dann müssen wir aber ohne Standardalgorithmen auskommen:

    #include <algorithm>
    #include <iterator>
    #include <map>
    #include <iostream>
    
    typedef std::map<int, bool> IntBool;
    typedef std::map<int, int> IntInt;
    
    int main(int argc, char* argv[])
    {
        IntInt ii;
        IntBool ib;
    
        ii[0] = 0;
        ii[1] = 1;
        ii[2] = 2;
        ii[3] = 3;
    
        for(std::map<int, int>::iterator iter1 = ii.begin(); iter1 != ii.end(); ++iter1)
            std::cout << iter1->first << " " << iter1->second << std::endl;
    
    //  std::transform(ii.begin(), ii.end(), std::inserter(ib, ib.end()), func);
        {
            std::map<int, int>::const_iterator iter1 = ii.begin();
            std::map<int, bool>::iterator iter2 = ib.begin();
            if ( iter1 != ii.end() && iter2 != ib.end() )
                for ( ;; )
                {
                    if ( iter1->first < iter2->first )
                    {
                        ib.insert( std::make_pair( iter1->first, false ), iter2 );
                        if ( ++iter1 == ii.end() )
                            break;
                    }
                    else
                        if ( ++iter2 == ib.end() )
                            break;
                }
            while ( iter1 != ii.end() )
                ib.insert( std::make_pair( iter1->first, false ), ib.end() );
        }
    
        for(std::map<int, bool>::iterator iter2 = ib.begin(); iter2 != ib.end(); ++iter2)
            std::cout << iter2->first << " " << iter2->second << std::endl;
    }
    

    Das ist schneller zumindest dann, wenn M nicht 0 und nicht sehr groß gegen N ist. Will man die beste Lösung, müsste man wohl zuerst die Größen der Maps untersuchen, und in Abhängigkeit davon dann den Algorithmus auswählen.


Anmelden zum Antworten