Alle Elemente im Container gleich?



  • Bashar schrieb:

    Für Mathematiker:

    set{c.begin(), c.end()}.size() <= 1
    

    Das ist schön! 👍



  • Wie waere es mit rotate_copy + equal?



  • Bashar schrieb:

    Für Mathematiker:

    set{c.begin(), c.end()}.size() <= 1
    

    Das ist schön, aber hat unnötig hohe Komplexität und kein Short Circuit.

    Sone schrieb:

    equal(begin(c), prev(end(c)), next(begin(c)))
    

    Das braucht BidirectionalIterator , theoretisch würde InputIterator ausreichen.

    Ich schlage vor:

    template<class InputIt]
    bool all_equal(InputIt first, InputIt last) {
        if(first == last) return true;
    
        typedef decltype(*first) T;
        T elem = *first++;
        return find_if(first, last, [&](const T& e) { return e != elem }) == last;
    }
    

    Wenn man die Kopie vermeiden möchte, kann man e == *first als Prädikat nehmen, aber dann braucht man wieder ForwardIterator .



  • ipsec schrieb:

    Bashar schrieb:

    Für Mathematiker:

    set{c.begin(), c.end()}.size() <= 1
    

    Das ist schön, aber hat unnötig hohe Komplexität und kein Short Circuit.

    Ich denke mal, spätestens seit der sort-unique-Lösung sind wir beim spaßigen Teil des Abends angelangt...



  • And the winner is...



  • knivil schrieb:

    Noch klarer wäre allerdings eine Schleife

    Jein.

    Vergleich: In der Funktionalen Programmierung...

    Oh Entschuldige. Ich war nicht im exakt Modus. Das haben wir gleich:

    "Noch klarer wäre allerdings in C++ eine Schleife".

    C++ bietet kein kurze und klare Syntax für die hier gnannten Sachen im funktionalen Programmierstil. Funktionale Programmierung in C++ ist deswegen low-level total hässlich. Natürlich verbietet dir niemand eine schön funktionale Implementation von equal_elements zu machen, aber unterhalb dieser Abstraktion ist die klarste Lösung eben die Schleife.

    template<class Range>
    bool all_equal(Range const& range){
        for(auto& x: range){
            if(x != range.front())
                return false;
        }
        return true;
    }
    


  • *auto&



  • Danke. kann gut sein, ich verwende keine c++11 features. Ich korrigiere das mal 🙂



  • Das verhindert, dass du die Elemente bei jedem Durchlauf kopierst.



  • otze, ich weiß nicht, ob du knivils Argument verstanden hast. Er hat nicht gesagt, du sollst funktional programmieren. Es war eine Analogie: In der funktionalen Programmierung vermeidet man nackte Rekursion zugunsten von Funktionen höherer Ordnung; entsprechend sollte man in der imperativen Programmierung nackte Schleifen vermeiden und generische Algorithmen verwenden.



  • Bashar schrieb:

    entsprechend sollte man in der imperativen Programmierung nackte Schleifen vermeiden und generische Algorithmen verwenden.

    Die Botschaft hör' ich wohl, allein mir fehlt der Glauben.

    Man sollte erstmal das Werkzeug verwenden, welches für das Problem angemessen ist. So gut wie alle hier präsentierten Lösungen haben irgendeinen mehr oder weniger graviernden Nachteil: zu hohe Anforderungen an den Iterator, zu hohe komplexitätsklasse, kein early exit, schwer zu verstehen, komplexe Syntax.

    Und ich werfe dagegen das range based for in den Ring, welches die Syntaxzucker-variante des funktional-generischen std::for_each algorithmus ist :).



  • Sone schrieb:

    Kommt schon.

    std::all_of(c.begin(), c.end(), [&c] (T elem) { return elem == c.front(); })
    

    vs

    std::equal(std::begin(c), std::prev(std::end(c)), std::next(std::begin(c)))
    

    Das ist doch kein Vergleich.

    Sehe ich auch so.

    "Prüfe für alle Elemente, ob sie gleich dem vordersten Element sind"
    

    vs.

    "Prüfe das Intervall vom Anfang bis ein Element vor dem Ende mit dem gleich langen Intervall beginnend ein Element nach dem Anfang auf Gleichheit"
    + Gedankenschritt, dass dies äquivalent ist mit "alle Elemente sind gleich"
    

    Kein Vergleich, absolut nicht. 💡



  • template <typename It>
    bool allEqual(It begin, It end)
    {
    	if(begin == end)
    		return true;
    
    	std::vector<typename std::iterator_traits<It>::value_type> other;
    	std::rotate_copy(begin, std::next(begin), end, std::back_inserter(other));
    	return std::equal(begin, end, other.begin());
    }
    

    😋



  • Geht es jetzt um den kompliziertesen Algorithmus?



  • Marthog schrieb:

    Geht es jetzt um den kompliziertesen Algorithmus?

    Guten Morgen! Willst'n Kaffee? 😋

    @Nexus: Gut stimmt. Vor allem deswegen, weil es theoretisch auch langsamer ist... (zusaetzlicher Iterator-Inkrement in jedem Schleifendurchlauf).


Anmelden zum Antworten