Brauche Entscheidungshilfe für das Einlesen einer Datei



  • Hallo, hab folgendes Problem:

    Ich hab eine Datei die folgendermaßen Aussieht:
    Hersteller Modell Wert1 ... Wert6

    Diese Datei wird wohl so um die 200 Zeilen (20 Hersteller mit je 9- 11 Modellen) haben und nun ist die Frage, wie ich sie einlese, bzw. was sinnvoller ist. Speichere ich alles in Arrays oder in eine Klasse?

    Funktion des Programms: Der Benutzer soll zuerst eine Auswahl aller Hersteller erhalten und dann sein jeweiliges Modell aussuchen. Durch Eingabe weiterer Parameter sollen ihm verschiedene Dinge berechnet werden.

    Wie geh ich das am besten an? Bei ner Klasse wär ich mir nicht ganz sicher, wie sich das realisieren lässt, da ja jeder Hersteller ein Objekt wäre und jedes Modell wiederrum, was eine Klasse in einer Klasse wäre.
    Wie könnte ich das am geschicktesten angehen?



  • Hi!

    class Model
    {
    public:
      // Methode zum serialisieren, etc...
    };
    
    class Hersteller
    {
    private:
      vector< Model *> modelList;
    
      // Methode zum serialiseren, etc...
    };
    

    So in der Art könntest du es machen.

    grüße



  • Ich könnt ja eigentlich auch nen 3-dimensionalen Vektor machen, oder geht das nicht? Bisher hatte ich nur 2-dimensionale, wie müsste ich denn dann dies Syntax ändern?

    vector< vector<char> > Name(Größe1, vector<char>(Größe2));
    

    Für die 1. und 2. Dimension bräuchte ich char, für die 3. float.



  • pippo schrieb:

    Für die 1. und 2. Dimension bräuchte ich char, für die 3. float.

    Häh? Kannst du den Satz mal etwas genauer erklären?

    (als Index für den vector sind nur int's erlaubt - char's könntest du notfalls umwandeln, aber mit float's dürfte das schwieriger werden.



  • pippo schrieb:

    Ich könnt ja eigentlich auch nen 3-dimensionalen Vektor machen, oder geht das nicht? Bisher hatte ich nur 2-dimensionale, wie müsste ich denn dann dies Syntax ändern?

    vector< vector<char> > Name(Größe1, vector<char>(Größe2));
    

    Für die 1. und 2. Dimension bräuchte ich char, für die 3. float.

    Warum leicht wenns auch umständlich geht... 🙄



  • Zugegriffen wird natürlich nur über int, aber die Daten die gespeichert werden, sind eben char, char und float

    @ David
    Ich finds so wesentlich einfacher 😉



  • Da brauchst du doch nur einen eindimensionalen Vektor von structs:

    struct object
    {
      char v1,v2;
      float v3;
    };
    
    vector<object> myvec;
    


  • Kann man irgendwo nachlesen, wie genau man das macht? Mir ist nicht ganz klar, wie das funktioniert



  • pippo schrieb:

    Kann man irgendwo nachlesen, wie genau man das macht? Mir ist nicht ganz klar, wie das funktioniert

    Wie man was macht? Structs?
    Das sollte eigentlich in deinem Buch oder Tutorial stehen.
    Ansonsten, kurz zur Verwendung:
    http://tutorial.schornboeck.net/struct.htm
    http://www.volkard.de/vcppkold/datenstrukturen.html



  • Wie ich ne Klasse mach, ist mir schon klar. Nur wie mach ich es so, dass diese dynamisch erzeugt wird. Und vor allem wird mir aus dem letzten Beispiel von CStoll nicht klar, wie die ganzen Vektoren unterschieden werden. Ich hab ja 20 verschiedene Hersteller ( v1 ) und je 9-11 Modellen ( v2 ) mit 7 Werten ( v3 ).
    Wie kann ich da nun sagen, ich will von Hersteller xy das Modell z?



  • Ich denke mal das du statt char eher string brauchst für die Hersteller bzw. Modellnamen. Desweitere structs mit vectoren. Etwa so

    struct Modell
    {
       string name;
       vector<double> werte;
    };
    
    struct Hersteller
    {
       string name;
       vector<Modell> modelle;
    };
    

    Zentral hast du dann einen vector<Hersteller> in dem du dann alles verwaltest. Die structs benötigen evtl. noch Zugriffsfunktionen sowie Konstruktoren.



  • pippo schrieb:

    Ich hab ja 20 verschiedene Hersteller ( v1 ) und je 9-11 Modellen ( v2 ) mit 7 Werten ( v3 ).
    Wie kann ich da nun sagen, ich will von Hersteller xy das Modell z?

    Dann hast du einen Vektor oder ein Array das aus 20 Elementen besteht. Jedes dieser Elemente setzt sich aus einer Struct zusammen, die die Modelle bzw. die Werte beinhaltet.
    D.h. du greifst auf das gewünschte Listenelement zu, und dann kannst du direkt auf die struct zugreifen.



  • Hallo Pippo,

    das ist ein Standard-Problem, welches man am besten auch mit Standard-Mitteln löst. Natürlich solltest Du Dir eine Klasse bauen, die einen Artikel oder so abbildet.

    class Artikel;
    

    Der verpasst man streaming-Operatoren, so dass man ein Objekt Artikel einlesen und ausgeben kann.

    class Artikel
    {
    public:
        friend std::istream& operator>>( std::istream& in, Artikel& a );
        friend std::ostream& operator<<( std::ostream& out, const Artikel& a );
    };
    

    Dann geht nämlich

    Artikel a;
        cin >> a;
        cout << "ein Artikel: " << a << endl;
    

    Damit ist schon viel gewonnen und das Einlesen in einen STL-Container (hier ein vector) geht in wenigen Zeilen:

    int main()
    {
        using namespace std;
        ifstream file("input.txt");
        vector< Artikel > artikel;
        copy( istream_iterator< Artikel >( file ), istream_iterator< Artikel >(), back_inserter( artikel ) );
    

    danach forderst Du den werten User auf, einen Hersteller anzugeben und gibst alle Artikel von diesem Hersteller aus

    cout << "Hersteller: ";
        std::string hersteller;
        cin >> hersteller;
        remove_copy_if( artikel.begin(), artikel.end(), ostream_iterator< Artikel >( cout, "\n" ), 
            IsNotHersteller( hersteller ) );
        cout << "---\n" << endl;
    

    Das remove_copy_if muss man sich wie ein "erstelle neue Liste und kopiere dorthin nicht was nicht von dem Hersteller ist" vorstellen - 2mal nicht.

    Genau so das Model

    cout << "Model: ";
        std::string model;
        cin >> model;
        remove_copy_if( artikel.begin(), artikel.end(), ostream_iterator< Artikel >( cout, "\n" ), 
            IsNotHerstellerOrModel( hersteller, model ) );
        cout << "---\n" << endl;
    
        return 0;
    }
    

    .. fertig.

    Sieht die Datei so aus

    Adidas Schuh 9 12.45
    VW Sharan 1 2305.25
    Adidas Hemd 3 90.95
    VW Golf 9 1233.75
    VW Sharan 2 4530.25
    Adidas Sharan 0 0
    

    kommt folgende Ausgabe

    Hersteller: VW
    VW Sharan 1 2305.25
    VW Golf 9 1233.75
    VW Sharan 2 4530.25
    ---
    
    Model: Sharan
    VW Sharan 1 2305.25
    VW Sharan 2 4530.25
    ---
    

    Zum Schluß noch die Implementierung von Artikel und den beiden Funktoren nebst benötigten Includes

    #include <algorithm>    // remove_copy_if
    #include <fstream>
    #include <iostream>
    #include <iterator>     // ostream_iterator, back_inserter
    #include <string>
    #include <vector>
    
    class Artikel
    {
    public:
        std::string Hersteller() const { return m_hersteller; }
        std::string Model() const { return m_model; }
    
        friend std::istream& operator>>( std::istream& in, Artikel& a )
        {
            return in >> a.m_hersteller >> a.m_model >> a.m_wert1 >> a.m_wert6;
        }
        friend std::ostream& operator<<( std::ostream& out, const Artikel& a )
        {
            return out << a.m_hersteller << " " << a.m_model << " " << a.m_wert1 << " " << a.m_wert6;
        }
    
    private:
        std::string m_hersteller;
        std::string m_model;
        int m_wert1;
        double m_wert6;
    };
    
    struct IsNotHersteller
    {
        explicit IsNotHersteller( const std::string& hersteller ) : m_hersteller( hersteller ) {}
        bool operator()( const Artikel& a ) const
        {
            return a.Hersteller() != m_hersteller;
        }
    private:
        std::string m_hersteller;
    };
    
    struct IsNotHerstellerOrModel
    {
        explicit IsNotHerstellerOrModel( const std::string& hersteller, const std::string& model ) 
            : m_hersteller( hersteller ) 
            , m_model( model )
        {}
        bool operator()( const Artikel& a ) const
        {
            return !( a.Hersteller() == m_hersteller  &&  a.Model() == m_model );
        }
    private:
        std::string m_hersteller;
        std::string m_model;
    };
    

    die Member wert2 bis wert5 kannst Du selber noch einfügen

    Gruß
    Werner



  • Sorry, aber mit dem Code bin ich hoffnungslos überfordert.

    Mitlerweile hab ich in nem anderen Forum erfahren, wie ich ein 3D-Array mit vector erstelle, nur dummerweise ist es scheinbar nicht möglich, in den ersten beiden Dimensionen Zeichen mit Char und in der 3. Zahlen mit float zu speichern.

    Es kann doch nicht so schwer sein ein 3D-Array zu erzeugen, bei dem ich mir selbst raussuchen kann, was ich in jeder Dimension speichern will.



  • Hä?!

    Ein Vektor wird mit ganzzahligen Indizes adressiert. Du speicherst also Werte vom Typ X mit einem Index vom Typ Ganzzahl. Bei einem 3D-Vektor liegen in den ersten zwei Dimensionen Vektoren und in der dritten Dimension X.

    D.h. Du suchst Dir aus was der Vektor (1.) speichert: Vektoren (2.) von Vektoren (3.) von float z.B.

    Ausserdem, wie soll ein Rechner eine Indizierung feld[2.5] auflösen 😕

    Ich glaube du möchtest drei Vektoren von denen jeder etwas anderes speichert 😉

    EDIT: paar Korrekturen



  • Weiß nicht, wie ichs noch erklären soll, damit man es versteht 🙂

    So sieht die Textdatei aus:

    Hersteller1 Modell1 3 5 23,3 54,5 345,32
    Hersteller1 Modell2 3 5 34,4 216,4 3453,1
    Hersteller2 Modell1 1 4 7 9 0 4
    .
    .
    .
    Hersteller20 Modell9 3 5 7 8 4 3 64,4

    Nun will ich das ganze in einem Array speichern. Das kann doch nicht so schwer sein 🙂

    z.B. ein Array wie Kennwerte[1][2][3]

    Bei dem ganzen Spaß soll dann einfach ne Schleife durchlaufen. Sobald der Hersteller nicht mehr der gleiche ist, wird die 1. Dimension um 1 erhöht, die 2. Dimension kann bei jeder neuen Zeile erhöht werden und die 3. nachdem ein Wert eingelesen wurde. Bei jeder neuen Zeile fängt die 3. Dimension wieder bei 0 an, bei jedem neuen Hersteller die 2.

    Noch ausführlicher kann ichs leider nicht schildern



  • Das was du machen willst, ist so in C++ mit "normalen" Arrays nicht möglich.
    Aber schau dir doch mal Braunsteins Tipp an, das ist genau das was du haben willst.



  • pippo schrieb:

    Sorry, aber mit dem Code bin ich hoffnungslos überfordert.

    Schade, - hast Du denn mal versucht ihn zum Laufen zu bringen?

    pippo schrieb:

    Mitlerweile hab ich in nem anderen Forum erfahren, wie ich ein 3D-Array mit vector erstelle, nur dummerweise ist es scheinbar nicht möglich, in den ersten beiden Dimensionen Zeichen mit Char und in der 3. Zahlen mit float zu speichern.

    Stell Dir doch mal ein Schachbrett vor. Jemand gibt Dir die Aufgabe in der ersten Dimension also von links nach rechts Münzen hinzulegen und in der zweiten Dimension also von vorn nach hinten Heftklammern. Was liegt dann auf jedem Feld des Schachbretts? Und kann man danach noch erkennen, dass Du die Münzen von links nach rechts hingelegt hast und nicht von vorne nach hinten?

    pippo schrieb:

    Weiß nicht, wie ichs noch erklären soll, damit man es versteht 🙂

    Ich glaub' das haben hier alle verstanden 😉

    pippo schrieb:

    So sieht die Textdatei aus:

    Hersteller1 Modell1 3 5 23,3 54,5 345,32
    Hersteller1 Modell2 3 5 34,4 216,4 3453,1
    Hersteller2 Modell1 1 4 7 9 0 4
    .
    .
    .
    Hersteller20 Modell9 3 5 7 8 4 3 64,4

    Ist das richtig, dass die Fließkommazahlen mit ',' geschrieben sind und es unterschiedliche Anzahlen von Zahlen hinter Hersteller und Modell geben kann?

    pippo schrieb:

    Nun will ich das ganze in einem Array speichern. Das kann doch nicht so schwer sein

    Ist es auch nicht, siehe mein Code und die anderen Vorschläge.

    pippo schrieb:

    z.B. ein Array wie Kennwerte[1][2][3]

    von welchem Typ soll 'Kennwerte[1][2][3]' denn sein?

    Gruß
    Werner



  • Umgesetzt hab ichs noch nicht, da ich nicht den leisesten Schimmer habe, wie ich den Code in mein Programm einbringe.

    Wie meinst du das mit dem Schachbrett? Es ist ja nicht so, dass ich den Wert von der 1. Dimension und den der 2. addieren will und später wieder wissen, welcher als 1. dastand. Oder meinst, dass z.B. Array[1][3] das gleiche wär wie Array[3][1]? Dem ist ja nicht so, oder?

    Dass mit dem "," war ein versehen, dass es eine unterschiedliche Anzahl von Werten geben kann ist möglich, ja. Aber das sollte ja nix machen.

    Das mit dem Typ des Arrays ist eben mein Problem, ich wollte eben, dass die einzelnen Dimensionen unterschiedliche Typen sein können, aber das geht ja nicht.



  • Mit Vektoren geht das tatsächlich nicht, aber du könntest im äußersten Notfall eine map verwenden (wobei ich nicht sicher bin, wie exakt die mit floats's umgehen kann). Ansonsten solltest du einfach mal Werner's Code ausprobieren und sehen, was dabei herauskommt.


Log in to reply