das geht doch viel schöner ;) -> Codeschnippsel



  • Holla,

    der methode wird ein vector übergeben an dessen ende neue elemente hinzugefügt werden sollen. p ist ein vector der der nur aus 0en und 1en besteht.
    v ist ein vektor der einträge hat (eigentlich genau soviele wie p 1en hat).
    BeispieL.
    p = 1 0 1 0 1
    v = 5 2 9
    M zu beginn:
    M = 9 8 7 6 2
    M zu ende:
    M = 9 8 7 6 2 5 0 2 0 9
    also im grunde wird p an M gehängt und für jede 1 wird der nächste wert von v genommen. also angehängt wird: 5 0 2 0 9 weil ja p = 1 0 1 0 1 ist.

    Hier meine idee...

    void 
    Class::Insert(std::vector<double>& M, 
                         std::vector<double>& p,
                         std::vector<double>& v)
    {
        int el = 0;
        for(int i = 0; i < p.size(); i++)
        {
            if( p[i] != 0.0 )
                M.push_back(v[el++]);
            else
                M.push_back(0.0);   
        }
    }
    

    ich weiß ihr hab verbesserungsvorschläge 😉



  • Jain, eher eine Anmekrung:

    Ein vergleich auf 0.0 wird in den seltensten Fällen klappen. Wird wohl eher meist 0.000000001 oder ähnlich sein.



  • Hallo Mati,

    die Frage ist doch: was ist schön?
    zunächst mal so "handwerkliche" Sachen.
    - Insert ist keine Methode, sondern eine Funktion, da auf keinerlei interne Member von Class zugegriffen wird
    - Parameter die innerhalb der Funktion/Methode nicht verändert werden. sollten per const Referenz (oder Value) übergeben werden. (s. Scott Meyers)
    - es gibt einen 'signed/unsigned mismatch' da Du einen int (i) mit einem size_t (p.size()) vergleichst. Also für i besser std::size_t wählen
    - besser prefix-Inkrement (++i) statt postfix-Inkrement (i++); ist bei 'int' zwar egal, aber bei Iteratoren nicht immer (s. Scott Meyers)
    - Iteratoren sollten vor der Indizierung bevorzugt werden (ist wahrscheinlich auch schneller)

    Alles zusammen macht das:

    void Insert(std::vector<double>& M,
                         const std::vector<double>& p,
                         const std::vector<double>& v)
    {
        std::vector<double>::const_iterator el = v.begin();
        for( std::vector<double>::const_iterator i = p.begin(); i != p.end(); ++i )
        {
            if( *i != 0.0 )
                M.push_back(*el++);
            else
                M.push_back(0.0);  
        }
    }
    

    Man kann das ganze noch abstrahieren, wenn man auf die Typen - hier 'std::vector< double >' - verzichtet. Es muss ja auch nicht notwendigerweise ein vector weiter gefüllt werden. Mit Template-Technik geht das dann so:

    template< typename I1, typename I2, typename O >
    O Insert( I1 first, I1 last, I2 first2, O out )
    {
        for( ; first != last; ++first, ++out )
        {
            if( *first )
                *out = *first2++;
            else
                *out = std::iterator_traits< I2 >::value_type();
        }
        return out;
    }
    

    .. ist auch weniger Schreibarbeit. Der dazu gehörige Aufruf wäre dann:

    Insert( p.begin(), p.end(), v.begin(), back_inserter( M ) );
    

    .. und es ist auch keine Änderung des Codes notwendig, wenn aus p ein vector< bool > werden würde.

    kommen wir zurück zur Anfangsfrage: ist das schön?

    Ach und noch was: passt der Name 'Insert' ?

    Gruß
    Werner



  • .. bleibt noch die Variante für den Freak 🕶

    template< typename I2 >
    struct GetIfNotZero
    {
        typedef typename std::iterator_traits< I2 >::value_type result_type;
        explicit GetIfNotZero( I2 first2 ) : m_cur( first2 ) {}
        template< typename T1 >
        result_type operator()( const T1& x )
        {
            return x? *m_cur++: result_type();
        }
    
    private:
        I2 m_cur;
    };
    template< typename I2 >
    GetIfNotZero< I2 > getIfNotZero( I2 first2 )
    {
        return GetIfNotZero< I2 >( first2 );
    }
    

    Aufruf:

    std::transform( p.begin(), p.end(), std::back_inserter( M ), getIfNotZero( v.begin() ) );
    

    leider nicht ganz Standard-konform, da der Funktor Seiteneffekte hat (++m_cur).

    Gruß
    Werner



  • Werner Salomon schrieb:

    leider nicht ganz Standard-konform, da der Funktor Seiteneffekte hat (++m_cur).

    Mach doch einfach einen InputIterator draus...
    (Aber das IfNotZero gefällt mir gar nicht, hätte da lieber ein schlichtes get_if<Pred>. Oder besser noch einen input_switch_iterator<ControlIter, Pred, PassInputIter, FailInputIter> 😉 )



  • SUPER! Vielen dank.
    Ich weiß nicht wie es den anderen anfängern geht aber ich lerne durch solche Hilfe wirklich am meisten!
    Danke an euch und die Vorschläge die ihr gebracht finde ich super und werde sie mir genau zu Gemüte führen! _DANKE_

    Noch ne kleine Frage: Wie kann ich den dann einen Vergleich mit != 0.0 ansetzten der auf alle fälle korrekt läuft?

    Danke


Anmelden zum Antworten