Vorschläge für Datenstruktur erbeten.



  • Hallo,
    ich möchte einen Vokabeltrainer programmieren. Die Vokabeln sind in einer Textdatei gespeichert, in der Form:

    food, meal     Essen, Mahlzeit
    to put         setzen, stellen, legen
    to give        geben
    

    Das Trennzeichen für die Sprachen ist der Tabulator, die Worte sind bei mehreren Bedeutungen durch Kommata getrennt.

    Nun möchte ich mir Anregungen holen, wie Ihr die Vokabeln für den Programmablauf speichern würdet.
    Ich bin nicht gänzlich ideenlos, mir fällt im Moment ein:
    Eine Zeile könnte man als einen Datensatz ansehen, der aus zwei Spalten besteht:

    class Column
    {
    	vector <string> column;
    };
    
    class Dataset
    {
    	Column left, right;
    };
    

    So könnte man wählen, welche Sprache abgefragt und welche beantwortet wird.

    Welche Datenstruktur würdet Ihr wählen?
    Gruß,
    D.



  • Warum so kompliziert? Um die Daten erstmal festzuhalten würde ich eine Struktur anlegen, die in etwa so aussieht:

    ///// Unter MSVS-C++ das Alignment beachten! /////
    struct Vokabel
    {
         std::string eng;
         std::vector<std::string> deu;
    };
    

    Dann einfach einen Vektor der sich auf das Objekt der Struktur bezieht und ab geht die Post. Dann haste alles schön dynamisch in einem Vektor.



  • Das Problem ist, dass du nicht eine schöne 1:1-Abbildung von Schlüssel und Wert hast, sonst wäre std::map wohl der Container erster Wahl. Aber gibt es bei dir eine Richtung, in der du bevorzugt arbeitest (z.B. deutsch abfragen, englisch prüfen)? Dann kämst du einer Map schon nahe. Wenn du dann noch Synonyme trennst (für "Essen" und "Mahlzeit" zwei Einträge), kannst du jedem deutschen Wort eine Menge von englischen zuordnen.

    Wenn du beide Richtungen oft brauchst, wäre vielleicht Boost.Bimap eine Überlegung wert. Wobei du das eigentlich mit normalen Vectoren hinbekommst, wenn auch vielleicht weniger performant.



  • Das ganze soll möglichst universell sein, d.h. keine Festlegung auf eine konkrete Sprache (Englisch ist nur ein Beispiel), für beide Sprachen soll die Möglichkeit bestehen mehrere Bedeutungen abzuspeichern und die Abfragerichtung (z.B. Englisch->Deutsch, Deutsch->Englisch) soll ebenfalls beliebig sein.
    Eventuell wird das ein Open Source Projekt oder so, der User beliebiger Nationalität kann sich dann selbst seinen Vokabeltest in Form einer einfachen Textdatei(UTF8 Format) zusammenstellen.



  • Kóyaánasqatsi schrieb:

    Warum so kompliziert? Um die Daten erstmal festzuhalten würde ich eine Struktur anlegen, die in etwa so aussieht:

    ///// Unter MSVS-C++ das Alignment beachten! /////
    struct Vokabel
    {
         std::string eng;
         std::vector<std::string> deu;
    };
    

    Dann einfach einen Vektor der sich auf das Objekt der Struktur bezieht und ab geht die Post. Dann haste alles schön dynamisch in einem Vektor.

    Deinem Vorschlag nach würde für mich sowas in Frage kommen:

    struct Dataset
    {
         std::vector<std::string> left_column;
         std::vector<std::string> right_column;
    };
    

    Werde ich mal begrübeln, ob das vorteilhaft ist. 🙂



  • Mit meiner Methode und wide-char sollte das keine Probleme ergeben...



  • Okay. Du solltest als erstes davon wegkommen, zwei Spalten zu speichern. Diese müssen nämlich ständig synchron gehalten werden (gleiche Anzahl Elemente). Wenn du stattdessen eine Spalte mit jeweils zwei Wortmengen als Elementtyp hast, bist du schon flexibler.

    Mit "Wortmengen" meine ich eine Anzahl von Worten, da du ja pro Begriff nicht auf ein Wort beschränkt bist, sondern Synonyme nutzen kannst.

    typedef std::vector<std::string> Wortmenge;
    

    Hier einige Möglichkeiten:

    // Paar, das zwei Wortmengen verbindet. Nur zusammengesetzter Typ, keine zusätzliche Funktionalität.
    typedef std::pair<Wortmenge, Wortmenge> Eintrag;
    
    // Klasse, stärkere Kapselung, mehr Funktionen.
    class Eintrag
    {
        private:
            Wortmenge Begriff1;
            Wortmenge Begriff2;
    
        public:
            Eintrag(const std::string& KommaseparierteListeFuerWortmenge1,
                    const std::string& KommaseparierteListeFuerWortmenge2);
            void FuegeWort1Hinzu(const std::string& Wort);
            void FuegeWortmenge1Hinzu(const std::string& KommaseparierteListe);
    }
    

    Nur mal so als Anregung. Mit der Klasse kannst du schön alles kapseln, und dann zum Beispiel mit der folgenden Zeile einen neuen Eintrag erstellen.

    Eintrag NeuerEintrag("to put", "setzen, stellen, legen");
    


  • Nexus schrieb:

    typedef std::pair<Wortmenge, Wortmenge> Eintrag;
    

    Wie kommst du immer auf diese genialen Ideen?



  • Kóyaánasqatsi schrieb:

    Wie kommst du imemr auf diese genialen Ideen?

    So wahnsinnig genial ist das eigentlich gar nicht. Es liegt doch irgendwie nahe, für zwei zusammengehörige Dinge ein Paar zu verwenden, oder nicht? 😉

    Auf diese Weise muss man sich nicht für alles eine eigene Klasse schreiben (gleiches gilt für boost::tuple ). Obwohl ich das trotzdem oft tue, weil mir first und second für viele Fälle zu wenig aussagekräftig ist. Beim Beispiel hier würde ich sowieso eher die grosse Klasse verwenden. Vielleicht noch etwas sinnvollere Funktionsnamen wählen. 🙂


Anmelden zum Antworten