Problem mit Struktur in Eingabeschleife



  • Hi(gh)!

    In diesem Programm:

    /* Testprogramm für vector-Funktionen */
    
    #include<iostream>
    #include <vector>
    using namespace std;
    
    int main()
    {
      struct datum // zu String zusammengefasstes Anzeigendatum mit Häufigkeitszähler
      {
        string kaldatum;
        unsigned short int anzahl=0;
      };
      vector<datum> daten;
      datum kaldat;
      bool end=false; // Flag für Schleifenabbruch
      bool found=false; // Flag für Übereinstimmung in bereits vorhandenen Datums-Strings
      string d; // einzugebender Datums-String
      char a; // Antwort auf Frage nach Abbruch
      unsigned int i; // Zähler für Suchschleife
      unsigned int j;
      
      
      
      while (end == false)
      {
        i = 0;
        j = daten.size();
        cout << "Datums-String eingeben: ";
        cin >> d;
        while (found == false && i < j)
        {
          if (daten[i].kaldatum == d)
          {
            found == true;
            daten[i].anzahl++;
          }
          i++;      
        }
        if (found == false)
        {
          kaldat.kaldatum = d;
          daten.push_back(kaldat);
        }  
      
        cout << "Ende der Eingabe (j/n)? ";
        cin >> a;
        if (a == 'j') end = true;
      }
    
      cout << "Datum" << "\t" << "Häufigkeit" << endl;
      cout << endl;
      for (i=0; i<j; i++)
      {
        cout << daten[i].kaldatum << "\t" << daten[i].anzahl << endl;
      }
      
      return 0;
    }
    

    sollen Datumsangaben als Strings (DDMMYYYY) eingeben werden, wobei dieser Datums-String Bestandteil einer Struktur ist, die außerdem noch die Anzahl identischer eingebener Datums-Strings enthält. Nur wenn ein neu eingebener Datums-String noch nicht im Struktur-Vector enthalten ist, wird ein neues Strukturelement angelegt, ansonsten wird nur der Anzahl-Wert beim bereits vorhandenen Strukturelement um 1 erhöht.

    Nach beendeter Eingabe werden die vorhandenen Struktur-Elemente mit Datums-String und Anzahl ausgegeben.

    Wenn ich jetzt viermal denselben Datums-String (z. B. "20200101") eingebe, sollte am Ende angezeigt werden:

    Datum Häufigkeit

    20200101 4

    Tatsächlich bekomme ich:

    Datum Häufigkeit

    20200101 3
    20200101 2
    20200101 1

    Was habe ich falsch gemacht?

    Bis bald im Khyberspace!

    Yadgar



  • Du suchst eine std::map<std::string, int>? (meinetwegen auch eine std::unordered_map)



  • @wob sagte in Problem mit Struktur in Eingabeschleife:

    Du suchst eine std::map<std::string, int>? (meinetwegen auch eine std::unordered_map)

    Geht es nicht auch einfacher? Ich verstehe das nicht! Ich bin Anfänger!

    Jetzt muss ich erst einmal verstehen lernen, was Maps überhaupt sind... und ich komme immer weiter von Hölzchen auf Stöckchen, immer weiter weg von dem, was ich eigentlich vorhabe! Muss C++ lernen so laufen? Zumal C++ alle paar Jahre noch umfangreicher und noch komplizierter wird, so dass ich sämtliche Bücher, mit denen ich bis jetzt versucht habe, C++ zu lernen, eigentlich wegschmeißen kann...

    Bis bald im Khyberspace!

    Yadgar



  • Eine std::map gibt es schon ewig. Die ist auch im Standard von 1998 schon drin. Also 25 Jahre. Und das Konzept ist natürlich nochmal älter. Jedes vernünftige Buch über c++ sollte ne map erklären, egal wie alt.



  • @wob sagte in Problem mit Struktur in Eingabeschleife:

    Eine std::map gibt es schon ewig. Die ist auch im Standard von 1998 schon drin. Also 25 Jahre. Und das Konzept ist natürlich nochmal älter. Jedes vernünftige Buch über c++ sollte ne map erklären, egal wie alt.

    AUPPERLE: Die Kunst der Programmierung mit C++, 2. Auflage 2002 tut es nicht... und dabei ist die Schwarte schon über 1000 Seiten dick! Manchmal habe ich das Gefühl, deutschsprachige Programmierliteratur soll die Leute dumm halten...

    Zwischenzeitlich habe ich nach "C++ map tutorial" gegooglet und dabei etwas gefunden (https://thispointer.com/stdmap-tutorial-part-1-usage-detail-with-examples/) mit dem ich zumindest anfange zu begreifen, was es mit diesen maps auf sich hat... nur muss ich gleich leider ins Bett, da ich nicht will, dass mein Schlaf-Wach-Rhythmus weiterhin so aus dem Ruder läuft!

    Bis bald im Khyberspace!

    Yadgar



  • Hi(gh)!

    Es funktioniert! Mit einem Bruchteil des bisherigen Aufwands an Code:

    #include <iostream>
    #include <map>
    #include <string>
    #include <iterator>
    using namespace std;
    
    int main()
    {
      map<string, int> Daten;
      char a = 'n'; // Variable für Antwort, standardmäßig auf "nein"
      string datum; // einzelner einzugebender Datums-String
      
      while (a != 'j')
      {
        cout << "Bitte Datums-String eingeben: ";
        cin >> datum;
        if (Daten.insert(make_pair(datum, 1)).second == false)
          Daten[datum]++;
        cout << "Eingabe beenden (j/n)? ";
        cin >> a;
      }  
    
      map<string, int>::iterator it = Daten.begin();
      while (it != Daten.end())
      {
        cout << it->first << " :: " << it->second << endl;
        it++;
      }
    
      return 0;
    }
    

    Ein- und Ausgabe:

    Bitte Datums-String eingeben: 20200101
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200101
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200102
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200101
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200103
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200104
    Eingabe beenden (j/n)? n
    Bitte Datums-String eingeben: 20200103
    Eingabe beenden (j/n)? j
    20200101 :: 3
    20200102 :: 1
    20200103 :: 2
    20200104 :: 1

    So sollte das sein! Danke, wob und Varun von thispointer.com!

    Bis bald im Khyberspace!

    Yadgar



  • @Yadgar sagte in Problem mit Struktur in Eingabeschleife:

    if (Daten.insert(make_pair(datum, 1)).second == false)
      Daten[datum]++;
    

    Einfacher:

    ++Daten[datum];
    

    (wird automatisch mit 0 angelegt, wenn es noch nicht existiert - das if kann also komplett weg!)

    Deine Einleseschleife würde ich ja anders gestalten:

    cout << "Daten eingeben, Abbrechen mit 'ende' oder EOF\n";
    while (cin >> datum) {
       if (datum == "ende") break;
       ++Daten[datum];
    }
    

    Und für die Ausgabe würde ich eine range-for-Loop nehmen (viel einfacher lesbar als das map-iterator-Geraffel):

    for (const auto& [datum, count] : Daten) {
        cout << datum << " :: " << count << "\n";
    }
    

    Allerdings wird weder bei deinem Programm noch bei mir überprüft, ob überhaupt ein Datum eingegeben wird - und auch nicht, ob nicht es vielleicht der 35. Februar oder der 37. Nachdezember ist.

    Wahrscheinlich würde ich die Werte auf Kommandozeile einfach nach sort / unique schicken, also sowas wie sort werte.txt | uniq -c


Anmelden zum Antworten