2

EDIT: Code updated using tips from SO replies. I get no errors when compiling, the list prints empty. Quantities are not updating.

Original Post: This is for school and I can't seem to get it to increment the items. It opens the file successfully but then prints 0 for occurrences even though there are at minimum 1 for each item I enter in the menu. This isn't my entire code but it's the code for my class since I think that's likely where I went wrong. Additionally, my menu won't recognize invalid input even though the else portion of the if/else is there to catch it. It just enters an infinite loop of printing the menu. I am open to all feedback and/or links to resources better than Zybooks to teach me what I am missing here.

class ItemCounter {
private:
    map <string, int> itemFrequency;
    string inputFile = "CS210_Project_Three_Input_File.txt";
    string outputFile = "itemTracker.dat";
public:
    void loadInputFile() {
        ifstream file(inputFile);
        // OPEN conditions
        if (file.is_open()) {
            string itemName;
            while (getline(file, itemName)) {
                int itemQuantity = 0;
                // Update item count
                itemFrequency[itemName] += itemQuantity;

                // Exception check for string conversion
                try {
                    itemQuantity = stoi(itemName);
                }
                catch (const invalid_argument& e) {
                    cout << "Error: Invalid Entry Found in Input File." << endl;
                    continue;
                }
            }
            // Close open file
            file.close();
        }
        // Else statement if file won't open
        else {
            cout << "Error: Could Not Open Input File" << endl;
            cout << endl;
        }
    }
    // Function to save new data to external file
    void saveOutputFile() {
        ofstream file(outputFile);
        if (file.is_open()) {
            for (auto& item : itemFrequency) {
                file << item.first << " " << item.second << endl;
            }
            file.close();
        }
        else {
            cout << "Error: Could Not Open Output File - Data Not Saved" << endl;
            cout << endl;
        }
    }

    // Function to display item occurrences
    void displayItemCount(string itemName) {
        int count = itemFrequency[itemName];
        cout << "Total Item Occurances for " << itemName << ": " << count << endl;

    }

    //Function to count and display total item counts of whole list
    void displayTotals () {
        for (auto& item : itemFrequency) {
            cout << item.first << " " << item.second << endl;
        }
    }

    // Function to count items in the list and print as histogram
    void displayItemsHistogram() {
        for (auto& item : itemFrequency) {
            cout << item.first << " ";
            for (int i = 0; i < item.second; i++) {
                cout << "*";
            }
            cout << endl;
        }
    }
};
    // Function to save new data to external file
    void saveOutputFile() {
        ofstream file(outputFile);
        if (file.is_open()) {
            for (auto& item : itemFrequency) {
                file << item.first << " " << item.second << endl;
            }
            file.close();
        }
        else {
            cout << "Error: Could Not Open Output File - Data Not Saved" << endl;
            cout << endl;
        }
    }
};

int main() { 
    ItemCounter itemCounter;
    itemCounter.loadInputFile();
    itemCounter.saveOutputFile();
    int menuChoice = 0;

    while (menuChoice != 4) {
        cout << "Main Menu" << endl;
        cout << endl;
        cout << "1. Stuff" << endl;
        cout << "2. Stuff" << endl;
        cout << "3. Stuff" << endl;
        cout << "4. Exit" << endl;
        cout << "Please make a selection: ";
        cin >> menuChoice;
        cout << endl;

        if (menuChoice == 1) {
            string itemName;
            cout << "Enter search term: ";
            cin >> itemName;
            cout << "FIX ME:" << endl;
        }

        else if (menuChoice == 2) {
            cout << "FIX ME" << endl;
        }

        else if (menuChoice == 3) {
            cout << "FIX ME" << endl;
        }
            
        else if (menuChoice == 4) {
            cout << "Program Terminated" << endl;
        }
        else {
            cout << "Invalid Selection, try again." << endl;
        }
    }
    return 0;
}

Read in data from file errors

Display list from file quantity fails to update

K_B
  • 33
  • 4
  • 5
    `int itemQuantity; itemFrequency[itemName] += itemQuantity;` What value do you expect `itemQuantity` to have here? What value should it have? – Nathan Pierson Jun 16 '23 at 21:50
  • Using `std::istringstream` and `std::unordered_map` would eliminate chunks of the code you have now. There wouldn't need to be any checking of spaces, and the counter automatically gets incremented. – PaulMcKenzie Jun 16 '23 at 21:53
  • @Nathan -- int itemQuantity starts at 0 and increments as the entered itemName is read from the list in the txt file. – K_B Jun 16 '23 at 21:57
  • `std::string word; std::istringstream strm(line); while (line >> word) { itemFrequency[itemWord]++; }` -- No need for `substr()`, no need to check for spaces, and the error pointed out in the comment by @NathanPierson doesn't show up. Also, the `itemQuantity` is simply `itemFrequency.size();` – PaulMcKenzie Jun 16 '23 at 21:57
  • 1
    @K_B That is incorrect. `itemQuantity` starts with an indeterminate value because you didn't initialize it. It sounds like your goal was for `itemFrequency[itemName]` to start at `0` and go up by `1` each time `itemName` is read. But that's not what you wrote. – Nathan Pierson Jun 16 '23 at 21:59
  • Note: You don't need to explicitly call `close` on a file stream in this scenario; the destructor will take care of this. (It's not wrong to do this though.) – fabian Jun 16 '23 at 21:59
  • @PaulMcKenzie our course has us putting "using namespace std;" at the top of our code so that's why I don't have std in front of everything. I will look up the other bits you suggested and see if that helps my brain. – K_B Jun 16 '23 at 22:00
  • @K_B *our course has us putting "using namespace std;" at the top of our code* -- Given that this is inline inside a `class`, your course is teaching bad habits. The `using namespace std;` should never go in a header file. – PaulMcKenzie Jun 16 '23 at 22:02
  • A [`std::stoi`](https://en.cppreference.com/w/cpp/string/basic_string/stol) is probably missing from your code... – fabian Jun 16 '23 at 22:02
  • @PaulMcKenzie -- our course is 100% teaching us bad habits, I've been told this before. @fabian -- I had a try/catch in my code with `try { itemQuantity = stoi(itemCountStr); } catch (const invalid_argument& e) { cout << "Error: Invalid Entry Found in Input File." << endl; continue; }` But I deleted it, probably against my better judgement – K_B Jun 16 '23 at 22:08
  • https://stackoverflow.com/a/37480108/920069 has a basic example of how to handle bad input. You can search for many more examples. – Retired Ninja Jun 16 '23 at 22:12
  • What is the format of your input like? `itemQuantity = stoi(itemName);` doesn't make a lot of sense. `itemName` is presumably a string like `"Apples"`, which cannot be converted into an integer. – Nathan Pierson Jun 17 '23 at 01:11
  • @NathanPierson I thought that I was basically converting it to a number so I could add them together and get the total count of apples. Or total count of onions. This is for a grocery store counting the number of each items sold in a day. – K_B Jun 17 '23 at 01:24
  • Basically converting _what_ to a number? What number should the string `"Apples"` be converted to? Or is the format of your input file something like `Apples 10 Pears 50 Squash 0` and you need code that will 1.) Read the value of `10` in and 2.) Convert it to the integer `10`? – Nathan Pierson Jun 17 '23 at 01:40
  • Ok, I see where you're going with this. The list is just a list of produce items. I want to count the amount of times a word is in the list. I threw out the conversion parts and changed it to an if statement but alas, no incrementing is happening. `if (file.is_open()) { string itemName; int itemQuantity = 0; while (file.peek() != EOF) { getline(file, itemName); // Update item count if (itemName == itemName) { itemFrequency[itemName] += itemQuantity; } ` – K_B Jun 17 '23 at 02:19
  • What do you think `itemFrequency[itemName] += itemQuantity;` is going to do if `itemQuantity` is 0? When do you think `if(itemName == itemName)` might possibly be false? – Nathan Pierson Jun 17 '23 at 03:37

1 Answers1

1

Issue with counting occurrences:

In the loadInputFile() function, you are initializing itemQuantity without assigning any value to it before using it to increment itemFrequency[itemName]. This means that you are incrementing with an uninitialized value, leading to incorrect results.

To fix this, you should convert itemCountStr to an integer and assign it to itemQuantity before incrementing itemFrequency[itemName].

Replace the line:

int itemQuantity;

with:

int itemQuantity = stoi(itemCountStr);

Issue with invalid input handling:

In the while loop in main(), if the user enters an invalid selection (a value other than 1, 2, 3, or 4), the program should not continue to print the menu indefinitely.

To address this, you can add a break; statement in the else block to exit the loop.

Replace:

else {
    cout << "Invalid Selection, try again." << endl;
}

with:

else {
    cout << "Invalid Selection, try again." << endl;
    break;
}

With these modifications, the code should now correctly increment the item occurrences, and handle invalid input by breaking out of the menu loop when necessary.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
john cena
  • 9
  • 3
  • Woooo!! Yah this works!! Woooo yah – john cena Jun 16 '23 at 22:16
  • I am still getting a return value of 0 when I enter the search term after changing the itemQuantity line. For the menu error, adding break terminates the program, but doesn't let the user enter another selection. – K_B Jun 16 '23 at 22:18