Sort mit mehreren Kriterien



  • Ich hab mir mal die Mühe gemacht, einen Code dafür zu schreiben, um dir Funktoren ein bisschen verständlicher zu machen 😉

    // Deine Klasse
    struct Obj
    {
    	short Age;
    	std::string Name;
    	Obj(short NewAge, const std::string& NewName);
    };
    
    Obj::Obj(short NewAge, const std::string& NewName)
    : Age(NewAge)
    , Name(NewName)
    {
    }
    
    // Funktor für Sortierung nach Name
    struct SortByName
    {
    	bool operator() (const Obj& Left, const Obj& Right);
    };
    
    bool SortByName::operator() (const Obj& Left, const Obj& Right)
    {
    	return (Left.Name < Right.Name);
    }
    
    // Funktor für Sortierung nach Alter
    struct SortByAge
    {
    	bool operator() (const Obj& Left, const Obj& Right);
    };
    
    bool SortByAge::operator() (const Obj& Left, const Obj& Right)
    {
    	return (Left.Age < Right.Age);
    }
    
    // Ausgabe des Vectors
    void OutputVec(const std::vector<Obj>& Vec)
    {
    	for (std::vector<Obj>::const_iterator i = Vec.begin(); i != Vec.end(); ++i)
    	{
    		std::cout << i->Name << " : " << i->Age << std::endl;
    	}
    	std::cout << std::endl;
    }
    
    int main()
    {
    	std::vector<Obj> Vec;
    	Vec.push_back(Obj(45, "A"));
    	Vec.push_back(Obj(102, "D"));
    	Vec.push_back(Obj(37, "C"));
    	Vec.push_back(Obj(19, "B"));
    
    	std::sort(Vec.begin(), Vec.end(), SortByAge());
    	OutputVec(Vec);
    
    	std::sort(Vec.begin(), Vec.end(), SortByName());
    	OutputVec(Vec);
    
    	std::cin.get();
    }
    


  • Hallo

    Danke für die viele Antworten, aber es hängt gerade ein wenig. Ich habe leider noch nicht mit Funktoren gearbeitet.

    Ich benutzte eine normale class.

    Braucht man diesen Konstruktor überhaupt?

    Obj::Obj(short NewAge, const std::string& NewName) 
    : Age(NewAge) 
    , Name(NewName) 
    { 
    }
    

    Gibts da keine einfachere Methode?

    Danke



  • Ach die Lösung war mal wieder einfach...

    bool byname (Obj const v1, Obj const v2)
    {
       return (v1.Name < v2.Name);
    }
    

    Dann sortieren mit sort(vec.begin(), vec.end(), byname)

    Wieso macht ihr das so umständlich? 😕



  • Sobald du Datenmember hast, sollte zumindest ein Default ctor hin.
    Aber für ein Funktor brauchst du nicht unbedingt einen. Ausser du willst gewisse Daten übergeben, um die dann zu vergleichen. (Was öfters der Fall ist).



  • Typhoon schrieb:

    Braucht man diesen Konstruktor überhaupt?

    Obj::Obj(short NewAge, const std::string& NewName) 
    : Age(NewAge) 
    , Name(NewName) 
    { 
    }
    

    Gibts da keine einfachere Methode?

    Ich hab diesen Konstruktor als Argument bei push_back() benötigt. Je nachdem, wie du die Daten im Container abspeicherst, ist er natürlich nicht nötig.

    Typhoon schrieb:

    Ach die Lösung war mal wieder einfach...

    bool byname (Obj const v1, Obj const v2)
    {
       return (v1.Name < v2.Name);
    }
    

    Dann sortieren mit sort(vec.begin(), vec.end(), byname)

    Wieso macht ihr das so umständlich? 😕

    Weil wir dir Funktoren zeigen wollten. Das was du machst, ist ein einfacher Funktionszeiger. Funktoren (=Funktionsobjekte) sind aber flexibler, weil damit z.B. auch Parameter übergeben werden können. Aber du hast Recht, für deine Anwendung geht es auch mit Funktionszeigern. Trotzdem kannst du dir die Funktoren für die Zukunft merken 😉



  • @Typhoon: ich mache es auch immer über Funktoren. Wahrscheinlich einfach Gewohnheitssache.
    EDIT: und oft denkt man dann auch nicht daran dass es auch einfacher ginge, wenn man schonmal gewöhnt ist es mit Funktoren zu machen 🙂 /EDIT



  • Nexus schrieb:

    Funktoren (=Funktionsobjekte) sind aber flexibler, weil damit z.B. auch Parameter übergeben werden können.

    Dafür gibt es std::tr1::bind . Wenn man das zur Verfügung hat, sind Funktionsobjekte in den meisten Fällen überflüssig.

    Kleine Anmerkung, die vielleicht dem Verständnis der Funktionszeiger zuträglich ist: Dass Funktionsnamen implizit in Zeiger umgewandelt werden ist eine Vereinfachung (nicht falsch verstehen, sie ist natürlich standardkonform). Eigentlich „müsste“ es sort(vec.begin(), vec.end(), &byname) heißen.



  • [quote=".filmor]
    Kleine Anmerkung, die vielleicht dem Verständnis der Funktionszeiger zuträglich ist: Dass Funktionsnamen implizit in Zeiger umgewandelt werden ist eine Vereinfachung (nicht falsch verstehen, sie ist natürlich standardkonform). Eigentlich „müsste“ es sort(vec.begin(), vec.end(), &byname) heißen.[/quote]

    Warum gilt das eigentlich für Pointer auf Memberfunktionen nicht?



  • Weil Memberfunktionen einen "versteckten" Parameter haben, und zwar die Adresse des Objektes.

    Also
    void MeineKlasse::meineFunktion(int narf)

    ist eigentlich
    void meineFunktion(MeineKlasse* this, int narf)

    Die Adresser der Funktion reicht in diesem Fall also nicht, da die Adresse des Objektes fehlt.



  • @Fellhuhn: die Super-Spezialbehandlung function ref->function ptr ist ein C-Relikt. Mit T::F funktioniert es auch NICHT wenn die Funktion statisch ist, mit dem this Zeiger hat das also nix zu tun. Ich denke man wollte nicht eine Abschäulichkeit wiederholen die man für freie Funktionszeiger nur in Kauf genommen hat um mit C kompatibel zu bleiben.


Anmelden zum Antworten