Sortieren mit eigener Vergleichsfunktion



  • Hallo,

    ich habe einen vector<char*> table mit Zeigern auf diverse c-strings. Ich möchte nun diesen vector sortieren entsprechend der lexikografischen Sortierung der c-strings.

    stable_sort(table.begin(),table.end(), myCompare);
    

    Meine Vergleichsfunktion sieht so aus:

    bool myCompare(char* a, char* b)
    {
        return strcmp(a,b) < 0;
    }
    

    Anstatt strcmp würde ich jetzt aber lieber strncmp verwenden, da ich immer nur eine bestimmte mir bekannte Anzahl an chars vergleichen muss. Dafür müsste myCompare noch ein drittes Argument bekommen, aber stable_sort will nur eine Vergleichsfunktion mit 2 Argumenten annehmen.
    Eine globale Variable wäre natürlich eine Lösung, um die Anzahl für myCompare bekannt zu machen, aber so will ich das eigentlich nicht lösen... gibt es noch andere Wege??



  • Bau ein Funktionsobjekt. Etwa

    class prefix_compare {
    public:
      prefix_compare(std::size_t n) : n_(n) { }
    
      bool operator()(char const *lhs, char const *rhs) const {
        return strncmp(lhs, rhs, n_) < 0;
      }
    
    private:
      std::size_t n_;
    };
    

    Es gibt in TR1, C++11 oder wahlweise Boost (abhängig davon, wie neu dein Compiler ist) eine Funktionsvorlage bind, die das inline kann:

    stable_sort(table.begin(),table.end(), bind(myCompare, _1, _2, n));
    

    Wobei bind in den Namensräumen std::tr1, std oder boost liegt, abhängig davon, welche Variante du benutzt. _1 und _2 sind ggf. in std::tr1::placeholders.



  • Entschuldigung, jetzt hab ich glatt die Verwendung des Funktionsobjektes vergessen:

    stable_sort(table.begin(),table.end(), prefix_compare(n));
    


  • Vielen Dank! Problem gelöst 🙂



  • In C++11 geht das übrigens auch richtig hübsch mit Lambda-Closures:

    #include <algorithm>
    #include <cstddef>
    #include <cstring>
    #include <iostream>
    #include <iterator>
    
    template<typename T, std::size_t N>
    std::size_t array_size(T(&)[N]) { return N; }
    
    int main() {
      char const * data[] = { "foo", "bar", "baz", "qux", "quux", "xyzzy" };
    
      std::size_t n = 2;
    
      std::stable_sort(data,
                       data + array_size(data),
                       [n](char const *lhs, char const *rhs) { // <-- hier
                         return std::strncmp(lhs, rhs, n) < 0;
                       });
    
      std::copy(data,
                data + array_size(data),
                std::ostream_iterator<char const *>(std::cout, "\n"));
    }
    

    Verfügbar in gcc seit 4.5 (wenn ich das richtig im Kopf habe) mit -std=c++0x und ab MSVC 2010. Welche anderen Compiler das ab welcher Version unterstützen ist mir nicht bekannt; es ist aber davon auszugehen, dass eventuelle Lücken da in absehbarer Zeit geschlossen werden - der neue Standard ist ja jetzt fertig.


Anmelden zum Antworten