fstream: Vokabeltrainer: Einlesung von text.txt funktioniert nur teilweise.



  • Problem gelöst!
    Wenn auch sehr umständlich. Ich werde mich bemühen den Code noch zu verbessern.

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <limits>
    using namespace std;
    
    void trainer(const string language){
    
        string mem;
        int right_w(0), false_w(0);
    
        ifstream in;
        in.open("text.txt");
        if (!in.is_open()) { cerr << "FEHLER: Datei konnte nicht geöffnet werden!" << endl;}
    
        string smem; //Für einzelne Vokabeln
        string s_all; //In diesen String wird die Datei "text.txt" komplett kopiert.
        vector<string> en_svec; //Vector für alle englishen Vokabeln.
        vector<string> de_svec; //Vector für alle deutschen Vokabeln.
    
        char character;
        char curr_language = 'd'; //Standartmäßig auf Deutsch
        while ((character = in.get()) != -1) {
            s_all += character;
        }
        for(size_t ix =0; ix != s_all.size(); ++ix){
            if(curr_language == 'd'){
    
                if(s_all[ix] == '\t' || s_all[ix] == '\n'){
                    if(s_all[ix] == '\t'){
                        curr_language = 'e';
                        continue;
                    }
                }
                else{
                    smem += s_all[ix];
                    if(s_all[ix+1] == '\t'){
                        de_svec.push_back(smem);
                        smem = "";
                    }
                }
    
            }
    
            else if(curr_language == 'e'){
    
                if(s_all[ix] == '\t' || s_all[ix] == '\n'){
                    if(s_all[ix] == '\n'){
                        curr_language = 'd';
                        continue;
                    }
                }
                else{
                    smem += s_all[ix];
                    if(s_all[ix+1] == '\n'){
                        en_svec.push_back(smem);
                        smem = "";
                    }
                }
    
            }
        }
        /*
        ////////////////////////////////////////////////////////////////////////////////////
        //Ausgabe von en_svec. Nur zum testen ob en_svec alle Elemente enthält!
        for(vector<string>::iterator iter = en_svec.begin(); iter != en_svec.end(); ++iter){
            cout << "Ausgabe en_svec in int main() :" << *iter << endl;
        }
        ////////////////////////////////////////////////////////////////////////////////////
    
        ////////////////////////////////////////////////////////////////////////////////////
        //Ausgabe von de_svec. Nur zum testen ob de_svec alle Elemente enthählt!
        for(vector<string>::iterator iter = de_svec.begin(); iter != de_svec.end(); ++iter){
            cout << "Ausgabe de_svec in int main() :" << *iter << endl;
        }
        ////////////////////////////////////////////////////////////////////////////////////
        */
    
        if(language == "de"){
            if((sizeof(en_svec)/sizeof(string)) == (sizeof(de_svec)/sizeof(string))){
                for(vector<string>::iterator de_iter = de_svec.begin(), en_iter = en_svec.begin(); de_iter != de_svec.end() && en_iter != en_svec.end(); ++de_iter, ++en_iter){ //backup:for(size_t ix=0; ix != (sizeof(de_svec)/sizeof(string)); ++ix){
                    cout << "Übersetze das Wort hinter dem Doppelpunkt. Ausgangssprache [ " << language << " ] : "
                         << *de_iter << endl;
                    cin >>  mem;
                    if(mem == *en_iter){
                        cout << "Richtig!" << endl;
                        ++right_w;
                        cin.clear();
                        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
                    }
                    else{
                        cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << *en_iter << endl;
                        ++false_w;
                        cin.clear();
                        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
                    }
                }
            }
            cout << "Ergebnis:\trichtig: " << right_w << "\tfalsch: " << false_w << endl;
        }
        else if(language == "en"){
            if((sizeof(en_svec)/sizeof(string)) == (sizeof(de_svec)/sizeof(string))){
                for(vector<string>::iterator de_iter = de_svec.begin(), en_iter = en_svec.begin(); de_iter != de_svec.end() && en_iter != en_svec.end(); ++de_iter, ++en_iter){ //backup:for(size_t ix=0; ix != (sizeof(de_svec)/sizeof(string)); ++ix){
                    cout << "Übersetze das Wort hinter dem Doppelpunkt. Ausgangssprache [ " << language << " ] : "
                         << *en_iter << endl;
                    cin >>  mem;
                    if(mem == *de_iter){
                        cout << "Richtig!" << endl;
                        ++right_w;
                        cin.clear();
                        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
                    }
                    else{
                        cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << *de_iter << endl;
                        ++false_w;
                        cin.clear();
                        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
                    }
                }
            }
            cout << "Ergebnis:\trichtig: " << right_w << "\tfalsch: " << false_w << endl;
        }
    
        /*
        cout << (sizeof(en_svec)/sizeof(string)) << endl; //liefert 3
        cout << (sizeof(de_svec)/sizeof(string)) << endl; //liefert 3
        */
    }
    
    int main()
    {
    
        string lang;
        cout << "Wähle die Sprache. [en] für English->Deutsch. [de] für Deutsch->Englisch" << endl;
        while(cin >> lang){
            if(lang == "de")
                break;
            else if(lang == "en")
                break;
            else{
                cerr << "FEHLER: Falsche Eingabe. Eingabe muss [en] oder [de] lauten!" << endl;
                continue;
            }
        }
        trainer(lang);
        return 0;
    }
    

    Edit: Hat jemand Verbesserungsvorschläge? Es gibt bestimmt viele...



  • Ich würde sagen die Funktion trainer ist etwas groß und erfüllt zu viele Aufgaben.

    Du könntest ganz leicht einbauen, dass die Textdatei nicht "gehardcoded" ist, sondern dass der Benutzer selbst bestimmt, welche Vokabeldatei er verwenden möchte. Dann kannst du immer für bestimmte Vokabeln bestimmte Dateien verwenden.
    Beachte hierbei, dass du auf den string mit dem Dateinahmen .c_str() anwendest, damit der istream damit was anfangen kann.

    Lies direkt aus der Datei deine Infos ein, nicht davor noch in einen riesen String kopieren oder sonst was machen. Das wurde aber glaube auch schon gesagt 😉

    if((sizeof(en_svec)/sizeof(string)) == (sizeof(de_svec)/sizeof(string)))

    if( en_svec.size() == de_svec.size())

    Einfach mal die Vorschläge der Vorposter nehmen, Map anstatt 2 Vektoren, ...

    mfg
    HarteWare



  • Keksman schrieb:

    ups. ja hast recht.
    habs jetzt in

    if((sizeof(en_svec)/sizeof(string)) == (sizeof(de_svec)/sizeof(string))){
    

    geändert.

    Hast du den Post von Skym0sh0 eigentlich gelesen?



  • Cyres schrieb:

    Keksman schrieb:

    ups. ja hast recht.
    habs jetzt in

    if((sizeof(en_svec)/sizeof(string)) == (sizeof(de_svec)/sizeof(string))){
    

    geändert.

    Hast du den Post von Skym0sh0 eigentlich gelesen?

    Ja habe ich.
    Allerdings hat mir Skym0sh0 vorgeschlagen

    if ( de_svec.siz() == en_svec.size() )
    

    zu benutzen. Ich wusste nicht was die Funktion siz() macht, also habe ich das vorerst ignoriert... Erst danach wurde mir klar, dass dies ein Tippfehler war. Ist mir erst relativ spät aufgefallen. Naja egal.
    Hier mal mein aktueller Code:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <limits>
    #include <stdexcept>
    using namespace std;
    
    int trainer(const string language, const string s1){
        string mem;
        int right_w(0), false_w(0);
    
        ifstream in(s1.c_str());
        if (!in.is_open()) { throw runtime_error("FEHLER: Datei konnte nicht geöffnet werden! Eventuell existiert die Datei nicht."); }
    
        string smem;
        vector<string> en_svec; //Vector für alle englishen Vokabeln.
        vector<string> de_svec; //Vector für alle deutschen Vokabeln.
    
        for(char character, curr_language = 'd'; (character = in.get()) != -1;){
            if(curr_language == 'd'){
                if(character == '\t'){
                        de_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'e';
                }
                else{ smem += character; }
            }
            else if(curr_language == 'e'){
                if(character == '\n'){
                        en_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'd';
                }
                else { smem += character; }
            }
        }
        in.close();
    
        if(language == "de"){        
            for(vector<string>::iterator de_iter = de_svec.begin(), en_iter = en_svec.begin(); de_iter != de_svec.end() && en_iter != en_svec.end(); ++de_iter, ++en_iter){
                cout << "Übersetze das Wort. STRG+D = Abbruch! Ausgangssprache [ " << language << " ] : "
                     << *de_iter << endl;
                if(!(cin >> mem)) { break; } //Abbruch mit STRG+D lautet(unter linux)
                if(mem == *en_iter){
                    cout << "Richtig!" << endl;
                    ++right_w;
                }
                else{
                    cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << *en_iter << endl;
                    ++false_w;
                }
            }
        }
        else if(language == "en"){
            for(vector<string>::iterator de_iter = de_svec.begin(), en_iter = en_svec.begin(); de_iter != de_svec.end() && en_iter != en_svec.end(); ++de_iter, ++en_iter){
                cout << "Übersetze das Wort. STRG+D = Abbruch! Ausgangssprache [ " << language << " ] : "
                     << *en_iter << endl;
                if(!(cin >> mem)) { break; } //Abbruch mit STRG+D(unter linux)
                if(mem == *de_iter){
                    cout << "Richtig!" << endl;
                    ++right_w;
                }
                else{
                    cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << *de_iter << endl;
                    ++false_w;
                }
            }
        }
        cout << "Ergebnis:\trichtig: " << right_w << "\tfalsch: " << false_w << endl;
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        cout << "Für Hilfe: ./Vokabeltrainer --help" << "\tProgramm abbrechen = STRG+C" << endl;
        string s1;
        if(argc > 1){
            s1 = argv[1];
            if(s1 == "--help"){
                cout << "Benutze: ./Vokabeltrainer <VOKABELQUELLE.txt>" << endl;
            }
        }
    
        string lang;
        cout << "Wähle die Sprache. [en] für English->Deutsch. [de] für Deutsch->Englisch" << endl;
        while(cin >> lang){
            if(lang == "de")
                break;
            else if(lang == "en")
                break;
            else{
                cerr << "FEHLER: Falsche Eingabe. Eingabe muss [en] oder [de] lauten!" << endl;
                continue;
            }
        }
        trainer(lang, s1);
        return 2;
    }
    

    Das Programm soll die Vokabeln außerdem noch zufällig aufrufen. Der Benutzer soll diese dann übersetzen. Mit srand() und rand() habe ich das schon versucht. Allerdings klappt dies nicht so wie ich es mir vorstelle. Wenn ich rand() schnell hintereinander aufrufe bekomme ich immer die gleiche Zahl. wenn ich ca 1 Sekunde warte, bekomme ich vielleicht, aber nicht immer eine andere Zahl.

    Die Abfrage ob de_svec genauso viele Elemente hat wie en_svec habe ich entfernt weil dies immer true ergeben würde. Hier die Erklärung:
    Das Ende meiner .txt sieht in meinem Texteditor "gedit" folgendermaßen aus:('\t' für Tabulator und '\n' für Zeilenumbruch)
    [/code]Buch\tbook\nTisch\t

    Ich dachte die ganze Zeit, dass das lette Zeichen ein '\t'. In wirklichkeit ist es aber ein '\n'. Warum hängt der dieses Zeichen an das Ende meiner .txt Datei an?
    [code="cpp"]for(char character, curr_language = 'd'; (character = in.get()) != -1;){
            if(curr_language == 'd'){
                if(character == '\t'){
                        de_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'e';
                }
                else{ smem += character; }
            }
            else if(curr_language == 'e'){
                if(character == '\n'){
                        en_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'd';
                }
                else { smem += character; }
            }
        }
    

    Nachdem das Programm den string "Buch" an den vector de_svec gehängt hat, setzt es curr_language auf 'e' weil das darauf folgende Wort normalerweise ein Englisches ist. Dies ist aber nicht der Fall. Das nachfolgende Zeichen in dem Fall das letzte von der *.txt Datei handelt es sich ja um ein '\n' Zeichen. Also wird der leere string smem an den vector en_svec gehängt. de_svec ist somit genau so groß wie en_svec.



  • srand muss am Anfang des Programms einmal aufgerufen werden, danach nie wieder (es sei denn du weisst was du machst und willst es auch so machen).

    rand kannst du danach beliebig aufrufen.

    Aber im neuen C++11 gibt es Zufallsgeneratoren.

    Aber mal ohne Spass, du machst mit Iteratoren und sowas allem rum, kensnt aber vector.size() nicht?



  • Aber mal ohne Spass, du machst mit Iteratoren und sowas allem rum, kensnt aber vector.size() nicht?

    Doch Doch Doch. Ich kenne den.

    Allerdings hat mir Skym0sh0 vorgeschlagen
    C++:
    if ( de_svec.siz() == en_svec.size() )

    zu benutzen. Ich wusste nicht was die Funktion siz() macht, also habe ich das vorerst ignoriert... Erst danach wurde mir klar, dass dies ein Tippfehler war. Ist mir erst relativ spät aufgefallen.

    Ich weiß nicht warum ich vector.size() nicht verwendet habe. Ich hatte da sowas mit sizeof noch im Kopf.

    if ( de_svec.siz() == en_svec.size() )
    

    Wenn du

    if ( de_svec.size() == en_svec.size() )
    

    geschrieben hättest, wäre ich drauf gekommen. ich hab nur nicht drüber nachgedacht, dass du mit siz() , size() meinst!

    for(char character, curr_language = 'd'; (character = in.get()) != -1;){
            if(curr_language == 'd'){
                if(character == '\t' || character == '\n'){
                    if(smem == "") { continue; }
                    else{
                        de_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'e';
                    }
                }
                else{ smem += character; }
            }
            else if(curr_language == 'e'){
                if(character == '\n' || character == '\t'){
                    if(smem == "") { continue; } //Wenn smem leer ist, wird die Schleife weiter ausgeführt.
                    else{
                        en_svec.push_back(smem);
                        smem = ""; //string reset
                        curr_language = 'd';
                    }
                }
                else { smem += character; }
            }
        }
        in.close();
        if(de_svec.size() != en_svec.size()) { throw runtime_error("FEHLER: *.txt Datei ist beschädigt!"); }
    

    So funktioniert es.
    Edit: Bitte nennt mir Dinge die an meinem Code nicht so gut sind. Ich weiß gerade überhaupt nicht wie ich den Zufallsgenerator in den Code einbauen könnte. Würde mir jemand einen Tipp geben?



  • Und jetzt guckste du dir mal std::map an und machst dein programm gleich mal um 75% kleiner und schneller.



  • Skym0sh0 schrieb:

    Und jetzt guckste du dir mal std::map an und machst dein programm gleich mal um 75% kleiner und schneller.

    Map ist hier völlig fehl am Platz. Das ist ein Fall für vector<pair<string,string> >



  • Mh, hört sich auch nicht schlecht an. Ja, ist echt gar nichtmal so schlecht.



  • Nimm boost::spirit.



  • Also,

    ich habe mir std::map mal angeguckt http://www.cplusplus.com/reference/map/map/
    und ein Unterverzeichnis http://www.cplusplus.com/reference/map/map/map/
    Ist das hier ein Anfang?

    vector < map<string,string> > de_en;
    

    Wenn ja, wie hänge ich Elemente dran?

    foo.push_back(("Hi")=("there!"));
    

    So ist es schonmal falsch. War ja auch geraten...

    Map ist hier völlig fehl am Platz. Das ist ein Fall für vector<pair<string,string> >

    ist da ein unterschied zu std::map?
    Ich bin gerade ein "bisschen" überfordert. Aus der Referenz werde ich einfach nicht schlau 😞



  • map ist ein assoziativer Container. Das heisst, du ordnest einem Key einen Value zu. Dabei können Key und Value (fast) beliebige Datentypen sein.
    Das kennst du im Prinzip schon vom Vector. Da hast du einem index (normalerweise ein vorzeichenloser Integer) einen Wert zugeordnet. Nichts anderes macht eine map.

    int main()
    {
    	std::map<std::string, double> m;
    	double bar = 1.618;
    
    	m["Test"] = 5.0f;
    	m["pi"] = 3.14159276;
    	m["foo"] = bar;
    
    	for(std::map<std::string, double>::iterator it = m.begin(); it != m.end(); ++it)
    	{
    		// it <-- std::pair<std::string, double>
    		std::cout << "m[" << it->first << "] = " << it->second << std::endl;
    	}
    
    	return 0;
    }
    

    Um mal einfachen Beispielcode zu zeigen. Iteratoren bieten ganz gerne ein bisschen was zum Stolpern, aber da kommt man drüber.

    Was unmap aber meint ist, dass diese map hier fehl am Platz ist.
    Er schlägt einen vector vor, der Paare von strings speichert. Das sieht dann so aus:

    int main()
    {
    	std::vector<std::pair<std::string, std::string>> vec;
    
    	// vector fuellen
    	vec.push_back(std::make_pair("tisch", "table"));
    	vec.push_back(std::make_pair("verdorbenheit", "depravity"));
    	vec.push_back(std::make_pair("belastung", "imposition"));
    	// ....
    
    	// hier kannst du dann deine vokabeln raten:
    	std::default_random_engine gen (seed);
    	std::uniform_int_distribution<int> rand(1, vec.size());
    
    	std::pair<std::string, std::string> question = vec[rand(gen)];
    
    	std::cout << "Was heißt \"" << question.first << "\": ";
    
    	std::string answer;
    	std::getline(std::cin, answer);
    
    	if ( answer == question.second )
    		std::cout << "Richtig!" << std::endl;
    	else
    		std::cout << "Falsch!" << std::endl;
    
    	return 0;
    }
    

    (Nur ausem Kopf geschrieben, grad beim Zufallsgenerator bin ich nicht sicher, da ich den bisher kaum geschrieben hab ;))



  • Danke für deine gute und schnelle Erklärung Skym0sh0 🙂
    Ich versuche mal std::map in meinen Code zu implementieren. Wenn mir das gelingt, versuche ich noch den vector zu implementieren, der wie du sagst Paare von strings speichert.
    Sooo ... Ich bin müde und gehe schlafen. Code kommt morgen.
    Gute Nacht.



  • Skym0sh0 schrieb:

    std::vector<std::pair<std::string, std::string>> vec;
    	
    	...
    	std::default_random_engine gen (seed);
    

    Grausam umständlich.
    unordered_map kann das alles schon, einfach iterieren für eine Trainingsfunktion und für einen normalen Übersetzungslauf dann [] (mit count() zur Absicherung bei Nichtexistenz);
    das alles leistet ein und dieselbe Datenstruktur, d.h. du brauchst für beide gängige Anwendungsfälle nicht immer eine neue aufzubauen und die ganzen Daten hin- und herkopieren.
    Alles viel kürzer und somit weniger fehleranfällig.



  • Mein aktueller Code:

    #include <iostream>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <limits>
    #include <stdexcept>
    
    #define ENG 0
    #define DEU 1
    
    using namespace std;
    
    int trainer(const string language, const string s1){
        unsigned int right_w(0), false_w(0);
    
        ifstream in;
        char c;
        string wordCache;
        vector < string > current;
        vector < vector < string > > vocab;
    
        in.open(s1.c_str()); // Open the file in read-only mode
        if (!in.is_open()) return 1; // Check whether it was opened successfully
    
        while ((c = in.get()) != -1) { // Walk through the file
            if (c == '\t' || c == '\n') { // Delimiter
                current.push_back(wordCache); // Add cached text to the array
                wordCache = ""; // Reset cache
            }
            else {
                wordCache += c; // Otherwise just append the current character to our word cache
            }
            if (c == '\n') { // In case we hit a newline,
                vocab.push_back(current); // Add the cached vocab pair to the vocab array
                current.clear(); // And don't forget to clear the vocab pair
            }
        }
    
        in.close();
        string mem;
        if(language == "de"){        
            for(unsigned int i=0; i < vocab.size(); ++i){
                cout << "Übersetze das Wort. STRG+D = Abbruch! Ausgangssprache [ " << language << " ] : "
                     << vocab.at(i).at(DEU) << endl;
                if(!(cin >> mem)) { break; } //Abbruch mit STRG+D(unter linux)
                if(mem == vocab.at(i).at(ENG)){
                    cout << "Richtig!" << endl;
                    ++right_w;
                }
                else{
                    cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << vocab.at(i).at(ENG) << endl;
                    ++false_w;
                }
            }
        }
        else if(language == "en"){
            for(unsigned int i=0; i < vocab.size(); ++i){
                cout << "Übersetze das Wort. STRG+D = Abbruch! Ausgangssprache [ " << language << " ] : "
                     << vocab.at(i).at(ENG) << endl;
                if(!(cin >> mem)) { break; } //Abbruch mit STRG+D(unter linux)
                if(mem == vocab.at(i).at(DEU)){
                    cout << "Richtig!" << endl;
                    ++right_w;
                }
                else{
                    cout << "Falsch!\t" << "Die richtige Vokabel lautet: " << vocab.at(i).at(DEU) << endl;
                    ++false_w;
                }
            }
        }
        cout << "Ergebnis:\trichtig: " << right_w << "\tfalsch: " << false_w << endl;
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        cout << "Für Hilfe: ./Vokabeltrainer --help" << "\tProgramm abbrechen = STRG+C" << endl;
        string s1;
        if(argc > 1){
            s1 = argv[1];
            if(s1 == "--help"){
                cout << "Benutze: ./Vokabeltrainer <VOKABELQUELLE.txt>" << endl;
                return 3;
            }
        }
    
        string lang;
        cout << "Wähle die Sprache. [en] für English->Deutsch. [de] für Deutsch->Englisch" << endl;
        while(cin >> lang){
            if(lang == "de")
                break;
            else if(lang == "en")
                break;
            else{
                cerr << "FEHLER: Falsche Eingabe. Eingabe muss [en] oder [de] lauten!" << endl;
                continue;
            }
        }
        trainer(lang, s1);
        return 2;
    }
    

    Diesen Code Abschnitt:

    while ((c = in.get()) != -1) { // Walk through the file
            if (c == '\t' || c == '\n') { // Delimiter
                current.push_back(wordCache); // Add cached text to the array
                wordCache = ""; // Reset cache
            }
            else {
                wordCache += c; // Otherwise just append the current character to our word cache
            }
            if (c == '\n') { // In case we hit a newline,
                vocab.push_back(current); // Add the cached vocab pair to the vocab array
                current.clear(); // And don't forget to clear the vocab pair
            }
        }
    

    habe ich nicht selber geschrieben. Mein c++ Wissen reichte einfach nicht aus(ca. 1 guten Monat am proggen).
    Ich wusste gar nicht, dass man einen vector der 2 Elemente hat an einen anderen vector anhängen kann.

    vocab.push_back(current);
    

    Macht

    current.clear();
    

    noch etwas anderes als alle Elemente von

    std::vector<string> current;
    

    zu löschen?

    #define
    

    kannte ich vorher auch noch nicht. Laut Google ist das ein Präprozessorobject.
    Ich versuch mich mal an <random>



  • Keksman schrieb:

    habe ich nicht selber geschrieben. Mein c++ Wissen reichte einfach nicht aus

    Das der anderen auch nicht.
    Grausames char-Gefrickel zum simplen Einlesen von Strings aus einer Textdatei.

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <unordered_map>
    
    using namespace std;
    
    int trainer(unordered_map<string,string> &d)
    {
      int fehler=0;
      for(unordered_map<string,string>::iterator i=d.begin();i!=d.end();++i)
      {
        cout << i->first << " ? ";
        string s;
        cin >> s;
        if( i->second==s )
        {
          cout << "Richtig\n";
        }
        else
        {
          fehler++;
          cout << "Falsch\n";
        }
      }
      return fehler;
    }
    
    int main()
    {
      string lang,d,e;
      cout << "Wähle die Sprache. [en] für English->Deutsch. [de] für Deutsch->Englisch" << endl;
      cin >> lang;
    
      ifstream f("text.txt");
      unordered_map<string,string> de,en; // vernünftige Programmiersprachen bieten von Haus aus natürlich auch bidirektionale Dictionaries an, da entfällt dann diese häßliche Daten-Dopplung
    
      while( f>>d && f>>e )
        de[d]=e,en[e]=d;
    
      cout << "Fehlerzahl: "  << trainer(lang=="de"?de:en);
    }
    

    unordered_map hat hier gegenüber vector<pair> den Vorteil, dass die Reihenfolge der abgefragten Vokabeln (meist) nicht der Reihenfolge in der Datei entspricht, und gegenüber map nicht sortiert abgefragt wird, das random-Zeugs also entfällt.



  • Die Streuung der Hashfunktion zur zufälligen Reihenfolge der Vokabeln zu verwenden finde ich ziemlich panne. 🙄
    Vor allem so wie du es machst, du nutzt die Map ja nichtmal zum Lookup.

    std::vector nehmen, die Pairs rein und std::random_shuffle. Fertig.



  • "Panne" ist, wenn man Wörterbuch-Aufgabenstellungen nicht mit Dictionaries löst und Anfängern, die wie hier Programmieren durch Ausprobieren praktizieren, mit allgemeinen Weisheiten über Vectoren kommt.
    Ich habe mal gehört, dass sich Daten zur Laufzeit eines Programms auch ändern können, und was machst du dann?
    Nach jedem Einfügen/Löschen nochmal Shuffle und den Gesamtdatenbestand anfassen?
    Und nichtindiziertes Löschen aus Vectoren praktizierst du wohl auch sehr gern.
    Natürlich kann man mit Vectoren auch ziemlich Ähnliches wie mit Dictionaries erreichen, man muss es aber nicht; und insbesondere nicht für Anfänger.
    Mit solchen "Qualitäts"vorstellungen bei C++ Datenstrukturen für Anfänger kannst du den üblichen Tutorialschreiberlingen/Fachbuchautoren/Hochschuldozenten/push_back-Fetischisten/... die Hand reichen.



  • Wutz schrieb:

    Nach jedem Einfügen/Löschen nochmal Shuffle und den Gesamtdatenbestand anfassen?

    Die unordered_map verändert die Reihenfolge der ursprünglichen Elemente dann auch nicht (immer), also müsste push_back reichen. Wenn ein mischen gewünscht ist, geht das mit (genau) einer unordered_map gar nicht.

    Wutz schrieb:

    Und nichtindiziertes Löschen aus Vectoren praktizierst du wohl auch sehr gern.

    swap(vec[i], vec.back()); vec.push_back();
    

    Wutz schrieb:

    Natürlich kann man mit Vectoren auch ziemlich Ähnliches wie mit Dictionaries erreichen, man muss es aber nicht; und insbesondere nicht für Anfänger.

    Die Dinger sind grundverschieden. Vector hat eine feste Reihenfolge, unordered_map ist halb-zufällig und kaum beeinflussbar.

    Mit solchen "Qualitäts"vorstellungen bei C++ Datenstrukturen für Anfänger kannst du den üblichen Tutorialschreiberlingen/Fachbuchautoren/Hochschuldozenten/push_back-Fetischisten/... die Hand reichen.

    dito



  • pfann schrieb:

    swap(vec[i], vec.back()); vec.push_back();
    

    Du meinst pop_back 😉

    @Wutz: Da du immer von Dictionaries redest, zeugt dass eher davon, dass du von einer Sprache wie C# oder Java kommst.

    Aber für das bisschen, was der TE hier erwartet, da reicht sowohl ein vector<pair<string, string> als auch eine map<string, string> als auch eine unordered_map<string, string>.

    Wie wir alle wissen hat ejde dieser Strukturen seinen Vor- oder Nachteil. Aber gerade weil eben so wenig Rahmenbedingungen bekannt sind (oder auch sogar nur vorhanden/verlangt), reicht das doch.


Anmelden zum Antworten