Struct sortieren



  • Hallo zusammen. Ich arbeite gerade an einem Projekt, bei dem verschiedene Methoden für eine Sammlung an PCs geschrieben werden. Bisher kam ich gut voran. Jetzt muss ich jedoch die PCs nach der Herstellernummer sortieren. Ich habe überhaupt keine Ahnung wie ich das machen soll. Die PCs befinden sich in einer Exelliste und sind als Struct definiert.
    Hier das Programm:
    Header-PC.h
    struct PC
    {

    unsigned Herstellernummer;
    int Leistung;
    int Gewicht;
    
    string Firma;
    string Name;
    string Farbe;
    string Betriebssystem;
    
    
    
    PC();
    void VonCSV(string l);
    

    };

    Header-pc_liste:

    //Klasse
    class PC_Liste
    {
    protected:
    
    PC nr[100];
    int anzahl;
    int index;
    
    public:
    
    //Konstruktor
    PC_Liste();
    
    //Getter
    PC GetTitel(int i);
    int GetAnzahl();
    int GetIndex();
    
    // Setter
    void operator++();      // ++index
    void operator--();      // --index
    void PlusZehn();        // index += 10
    void MinusZehn();       // index -= 10
    
    // Bearbeiten
    void Aendern();        // aktueller Titel
    void Loeschen();
    void Hinzufuegen();
    
    // Display
    void ZeigeUeberschrift();
    void ZeigePC(int i);
    void ZeigePC();
    void ZeigeZehn();
    void ZeigeAlle();
    // File IO
    void LeseDatei();
    void SchreibeDatei();
    

    };

    PC.cpp:

    PC::PC()
    {
        Herstellernummer=0;
        Name= "Unbekannter Name";
        Firma= "Unbekannte Firma";
        Leistung=0;
        Gewicht=0;
        Betriebssystem= "Unbekanntes Betriebssystem";
        Farbe= "Unbekannte Farbe";
    }
    
    void PC::VonCSV(string l)                    // Umwandlung aus CSV-String
    {
        istringstream input(l);
        string temp;
        input >> Herstellernummer;
        getline(input, temp, ';'); // Semikolon nach Platz wegwerfen
        getline(input, Name, ';');
        getline(input, Firma, ';');
        input >> Leistung;
        getline(input, temp, ';'); // Semikolon nach Platz wegwerfen
        input >> Gewicht;
        getline(input, temp, ';'); // Semikolon nach Platz wegwerfen
        getline(input, Betriebssystem, ';');
        getline(input, Farbe, ';');
    
        return;
    }
    

    PC_Liste.cpp:

    PC_Liste::PC_Liste()                    // Konstruktor
    {
        anzahl = 0;
        index = 0;
    }
    
    void PC_Liste::LeseDatei()                   // von Datei Lesen
    {
        cout << "anfang LeseDatei\n";
        anzahl = 0;
        string   line;
        ifstream hitDatei;
    
        // PC_Liste-Datei öffnen
        hitDatei.open("C:/Users/winkl/Documents/PC_sortieren/Data/PC_Liste.CSV");
        if (!hitDatei)
        {
            cout << "Datei Fehler!\n";
            return;
        }
        // PC_Liste aus Datei befüllen
        for (anzahl = 1; !hitDatei.eof() && anzahl < 100; ++anzahl)
        {
            getline(hitDatei, line);
            cout << "line: " << line << endl;
            nr[anzahl].VonCSV( line );
            cout<< nr[anzahl].Herstellernummer << "; " << nr[anzahl].Name << "; " << nr[anzahl].Firma <<"; " << nr[anzahl].Leistung
                 << "; " << nr[anzahl].Gewicht << "; " << nr[anzahl].Betriebssystem << "; " << nr[anzahl].Farbe << endl;
        }
    
        // Datei schließen
        hitDatei.close();
    
        cout << "ENDE LeseDatei\n";
    }
    
    void PC_Liste::SchreibeDatei()               // in Datei schreiben
    {
        cout<<"anfang schreiben \n";
        ofstream hitDatei;
    
        // PC_Liste-Datei öffnen
        hitDatei.open("C:/Users/winkl/Documents/PC_sortieren/Data/PC_Liste.CSV");
        if (!hitDatei)
        {
            cout << "Datei Fehler!\n";
            return ;
        }
    
        // PC_Liste aus Datei befüllen
        for (int i = 1; i < anzahl; ++i)
        {
            hitDatei << nr[i].Herstellernummer << ';' << nr[i].Name << ';' << nr[i].Firma << ';' << nr[i].Leistung<< ';' << nr[i].Gewicht<< ';'
                     << nr[i].Betriebssystem<< ';' << nr[i].Farbe << endl;
            cout<< nr[anzahl].Herstellernummer << "; " << nr[anzahl].Name << "; " << nr[anzahl].Firma <<"; " << nr[anzahl].Leistung
                 << "; " << nr[anzahl].Gewicht << "; " << nr[anzahl].Betriebssystem << "; " << nr[anzahl].Farbe << endl;
        }
    
        // PC_Liste-Datei schließen
        hitDatei.close();
    
        cout << "ENDE Schreibe Datei\n";
    }
    
    int PC_Liste::GetAnzahl()                    // Getter anzahl
    {
        return anzahl;
    }
    
    int PC_Liste::GetIndex()                     // Getter index
    {
        return index;
    }
    
    PC PC_Liste::GetTitel(int i)              // Getter Titel
    {
        return nr[i];
    }
    
    void PC_Liste::operator++()                  // ++ index
    {
        if (index < anzahl - 1)
            ++index;
    }
    
    void PC_Liste::operator--()                  // -- index
    {
        if (index) // > 0
            --index;
    }
    
    void PC_Liste::PlusZehn()                    // index += 10
    {
        if (index < anzahl - 11)
            index += 10;
    }
    
    void PC_Liste::MinusZehn()                   // index -= 10
    {
        if (index > 9)
            index -= 10;
    }
    
    void PC_Liste::ZeigeUeberschrift()           // Überschrift für Listenausgabe
    {
        cout << "\nIndex\t| Herstellernr.| Name               |Firma               |Leistung|Gewicht|Betriebssystem             |Farbe         \n";
        cout << "--------------------------------------------------------------------------------------------------------------------------------------\n";
    }
    
    void PC_Liste::ZeigePC(int i)             // Ausgabe eines PCs in der Liste
    {
        cout << i << "\t| " << nr[i].Herstellernummer;
        cout.width(14);
        cout << "| " << nr[i].Name;
        cout.width(5);
        cout << "| " << nr[i].Firma;
        cout.width(5);
        cout << "| " << nr[i].Leistung;
        cout.width(8);
        cout << "| " << nr[i].Gewicht;
        cout.width(7);
        cout << "| " << nr[i].Betriebssystem;
        cout.width(2);
        cout << "| " << nr[i].Farbe << endl;
    }
    
    void PC_Liste::ZeigePC()                  // Ausgabe eines PCs in der Liste
    {
        ZeigePC(index);
    }
    
    void PC_Liste::ZeigeZehn()                   // PC in der Umgebung des aktuellen anzeigen
    {
        ZeigeUeberschrift();
        for (int i=index-4;i<index+6;++i)
        {
            if (i==index)
            {
                cout << "------------------------------------------------------------------------------------------------------------------------------\n";
                ZeigePC(i);
                cout << "------------------------------------------------------------------------------------------------------------------------------\n";
            }
            else if (i>=0 && i<anzahl)
                ZeigePC(i);
        }
    }
    
    void PC_Liste::ZeigeAlle()                   // Alle PCs anzeigen
    {
        ZeigeUeberschrift();
        for (int i = 0; i < anzahl; ++i)
            ZeigePC(i);
    }
    
    void PC_Liste::Aendern()                     // Ändern des aktuellen PCs
    {
        int i=index;
    
        cout<<"\nPC hinzufügen \ngeben sie ein:\n";
        cout<<"Herstellernummer: ";
        cin>>nr[i].Herstellernummer;
        cout<<"Name: ";
        cin>>nr[i].Name;
        cout<<"Firma: ";
        cin>>nr[i].Firma;
        cout<<"Leistung: ";
        cin>>nr[i].Leistung;
        cout<<"Gewicht: ";
        cin>>nr[i].Gewicht;
        cout<<"Betriebssystem: ";
        cin>>nr[i].Betriebssystem;
        cout<<"Farbe: ";
        cin>>nr[i].Farbe;
    
    }
    
    void PC_Liste::Hinzufuegen()  //Eingabe über Tastatur der neuen PC-Daten
    {
    
        int i;
        //Prüfen ob PC hinzugefügt werden kann
        if (anzahl < 100)
                ++ anzahl;
        else
        {
            cout << "\n FEHLER: Array ist voll.\n";
            return;
        }
    
        //Alle PCs ab ausgewhltem index eins Weiterschieben
        for (i = anzahl-1; i>index; --i)
        {
            nr[i].Herstellernummer = nr[i-1].Herstellernummer;
            nr[i].Name = nr[i-1].Name;
            nr[i].Firma = nr[i-1].Firma;
            nr[i].Leistung = nr[i-1].Leistung;
            nr[i].Gewicht = nr[i-1].Gewicht;
            nr[i].Betriebssystem = nr[i-1].Betriebssystem;
            nr[i].Farbe = nr[i-1].Farbe;
        }
    
    
        //eingeben neue Daten
        Aendern();
    
    }
    
    
    void PC_Liste::Loeschen()                    // Löschen des aktuellen PCs
    {
        int i;
        for (i = index; i < anzahl-1; ++i)
        {
            nr[i].Herstellernummer = nr[i+1].Herstellernummer;
            nr[i].Name = nr[i+1].Name;
            nr[i].Firma = nr[i+1].Firma;
            nr[i].Leistung = nr[i+1].Leistung;
            nr[i].Gewicht = nr[i+1].Gewicht;
            nr[i].Betriebssystem = nr[i+1].Betriebssystem;
            nr[i].Farbe = nr[i+1].Farbe;
        }
        nr[i].Herstellernummer = 0;
        nr[i].Name = "";
        nr[i].Firma = "";
        nr[i].Leistung = 0;
        nr[i].Gewicht = 0;
        nr[i].Betriebssystem = "";
        nr[i].Farbe = "";
        --anzahl;
    }
    

    Jetzt muss ich die Werte aus der Liste irgendwie sortieren. Vielleicht kamm mit da jemand helfen.

    Gruß Simeon



  • Zum Sortieren kannst du std::sort verwenden: https://en.cppreference.com/w/cpp/algorithm/sort
    Dabei kannst du als letztes Argument einen eigenen sog. Funktor angeben der dann zum Vergleichen verwendet werden soll.
    Der Funktor muss true zurückliefern wenn das erste Argument in der gewünschten Reihenfolge vor dem zweiten Argument kommen soll.



  • @Sim-Wink sagte in Struct sortieren:

    PC nr[100];

    Benutze einen std::vector, kein Array.



  • @Sim-Wink sagte in Struct sortieren:

        for (anzahl = 1; !hitDatei.eof() && anzahl < 100; ++anzahl)
        {
            getline(hitDatei, line);
    
    

    Fail. Falsch:

    1. auf Lesefehler prüfen
    2. lesen
    3. gelesenes (ggf. quatsch) verarbeiten

    Richtig:

    1. lesen
    2. auf Lesefehler prüfen und ggf. abbrechen
    3. gelesenes verarbeiten
        for (anzahl = 1; anzahl < 100 && getline(hitDatei, line); ++anzahl)
    

    Weiters:
    Blöde Idee: Von Filestream in string lesen, string in Stringstream schieben, von Stringstream lesen
    Gute Idee: Von Filestream lesen.

    std::istream& operator>>(std::istream &is, PC &pc)
    {
        PC temp;
        if (!(is >> temp.Herstellernummer)
            return is;
        std::string trash;
        if (!getline(is, trash, ';')) return is;         // *)
        if (!getline(is, temp.Name, ';')) return is;
        if (!getline(is, temp.Firma, ';')) return is;
        if (!(input >> temp.Leistung)) return is;
        if (!getline(input, trash, ';')) return is;
        if (!(input >> temp.Gewicht)) return is;
        if (!getline(input, trash, ';')) return is;
        if (!getline(input, temp.Betriebssystem, ';') return is;
        if (!getline(input, temp.Farbe, ';')) return is;
    
        pc = temp;
        return is;
    }
    
    // ...
    std::ifstream input_file("foobar");
    if (!input_file.is_open() {
        // handle error
    }
    std::vector<PC> computers;
    for (PC pc; input_file >> pc; computers.push_back(pc))
        ;
    // ...
    

    * ) Dafür ist eigentlich istream::ignore() da



  • @Sim-Wink sagte in Struct sortieren:

    void PC_Liste::Loeschen()                    // Löschen des aktuellen PCs
    

    Ist auch eine blöde Idee. Suche nach erase & remove.



  • Noch eine andere Sache:

    Du solltest unbedingt Zuständigkeiten trennen.
    Die Lese-/Schreibfunktionalität sollte keine Eigenschaft der Liste sein, sondern als freie Funktion implementiert werden. Wenn irgendwann zB neue Formate dazukommen (INI, XML, JSON, Binary, etc) kannst du das bequem ergänzen, ansonsten blähst du deine Liste unnötig auf. Gilt natürlich auch für das Lesen aus eine CSV-Datei.
    Das gleiche gilt für die Anzeige. Die Liste selbst sollte sich nicht um die Anzeige kümmern, sondern irgendwas sollte die Liste anzeigen.
    Wozu der Index benutzt wird habe ich nicht verstanden, und damit auch nicht operator++, operator--, PlusZehn und MinusZehn.

    Wenn du das so umsetzt, wie gerade vorgeschlagen, sähe das Ganze so aus:

    struct PC
    {
       unsigned int Herstellernummer = 0;
       unsigned int Leistung = 0;
       unsigned int Gewicht = 0;
    
       std::string Firma;
       std::string Name;
       std::string Farbe;
       std::string Betriebssystem;
       
      PC() = default;
    }
    

    Die "Liste" aus PCs ist einfach nur std::vector<PC>, und fertig.

    // Lese- und Schreibfunktionalität
    
    // Lesen und Schreiben im "Default"- Format
    std::istream& operator>>( istream& is, std::vector<PC>& collection );
    std::ostream& operator<<( ostream& os, std::vector<PC> const& collection );
    
    // Lesen/Schreiben anderer Formate, naiver Ansatz
    std::vector<PC> read_from_csv( std::string const& filename );
    void write_to_csv( std::string const& filename , std::vector<PC> const& collection );
    
    std::vector<PC> read_from_xml( std::string const& filename );
    void write_to_xml( std::string const& filename , std::vector<PC> const& collection );
    
    // Anzeigefunktionen
    void show_pc( PC const& pc );                        // von mir aus auch einfach nur show, die richtige Überladung 
    void show_list( std::vector<PC> const& collection ); // wird durch wird durch den Parameter benutzt
    

    Zurück zum Index:
    Die Liste ist nicht dafür verantwortlich sich zu merken, welches Element gerade aktuell ist, das muss im eigenen Kontext irgendwo anders passieren.

    Edit:
    const correctness ist auch ein Thema, mit du dich beschäftigen solltest.