How to split strings and pass them to class vectors from file - c++

For my university class in programming we have been working on Object Oriented Programming (OOP) and are currently working on a group project. The project is to create a cash register that holds items with their names, amounts, and prices. As well as have a way to track the coins given by the user then determine the coin denomination. These are supposed to be done in different classes and involve objects.
My question is regarding the inventory manager that I am coding. The inventory manager is supposed to take the "data.txt" file and read it into the appropriate vectors. Currently I have a vector for the item name, price, amount, and then the itemList vector which holds a string of all 3 to print to the user for readability.
Here is a snippet from the data file:
20 1.99 Potato Chips
10 5.99 Ibuprofen
4 1.42 Candy
55 3.10 Coffee
12 3.25 Hummus
12 4.55 Guacamole
7 0.80 Baklava
45 1.50 Chocolate Chip Cookies
My question is, how do I split the line up so that I can pass the amount (first number) to the appropriate vector, pass the price to the appropriate vector, then pass the name to the appropriate vector. Essentially splitting each line into 3 parts. The part that is the most difficult to me is how the names of the items can be 1 word, 2 words, or even 3 words. Making it difficult to predict how many spaces the name will have, which caused a lot of my attempts to not work.
I found a working solution though I'm worried it's incorrect or inefficient and I'm curious in knowing the best way to do this. Thank you so much ahead of time and I will post the class definition and the method I'm working in down below.
< The stream object is inFile>
class inventoryManager
{
private:
double total, change, choice;
vector <int> amount;
vector <string> name;
vector <double> price;
vector <string> itemList;
public:
void fileOpen(fstream& inFile);
void fillInventory(fstream& inFile);
void printInventory(fstream& inFile);
};
void inventoryManager::fillInventory(fstream& inFile)
{
string temp;
string a, b;
while (!inFile.eof())
{
inFile >> a >> b;
amount.push_back(stoi(a));
price.push_back(stod(b));
getline(inFile, temp);
name.push_back(temp);
itemList.push_back(temp);
}
}
Attempted: I tried using the find() function to find each space then use the index to print the estimated indices to each side of the white space to the vectors. Though it was extremely messy and wouldn't work if a different data file was inputted. The idea of the program is to be able to work if a different file is put in, similar format but the amount could be 100, and prices could be more digits. I also tried editing the file directly by adding new lines for each space but ran into the item names with multiple spaces and ultimately didn't work.

You are trying to do too many new things at once. Break the problem into pieces and solve them separately, then combine them. To break the string into pieces you can use find and substr, you just have to be careful and debug until you're sure it's working perfectly:
string s = "45 1.50 Chocolate Chip Cookies";
cout << "s: " << s << endl; // for debugging
size_t first = s.find(' ');
cout << first << endl; // for debugging
string amountString = s.substr(0, first);
cout << amountString << "X" << endl; // for debugging
size_t second = s.find(' ', first+1);
cout << second << endl; // for debugging
string priceString = s.substr(first+1,second-first-1);
cout << priceString << "X" << endl; // for debugging
string nameString = s.substr(second+1);
cout << nameString << "X" << endl; // for debugging
The purpose of those X's is to be certain that the substring has no trailing space.
Once you have tackled the problem this way (and handed the result in for a grade), you can advance to tools like stringstream, and you won't have to deal with this grubby index arithmetic any more.

Related

How to swap and remove lines at output?

I am trying to out put the GPA based on their value. Highest GPA on top and Lowest GPA below. And also output 2 out of 5 of my output. Below is my output. As you can see, the person with the most GPA (3.9) is all the way below. is it possible to output him at the top followed by the second highest, third, fourth and so on. I got these data off a txt file.
Also if possible, I also need to print out only 3 out of he five with highest to lowest GPA. So 3 outputs with highest on top to lowest below out of the 5.
Apologies for the terrible code. I am very weak in this but am trying my very best.
This is my txt file. the first column is first choice, second choice, third choice, name, gpa.
CC,DR,TP,Alex Kong ,3.8
SN,SM,TP,Marcus Tan,4
DR,TP,SC,Asta Goodwin,3.6
SC,TP,DR,Malcum Yeo,2.8
SN,SM,TP,David Lim,3.7
and so on...
This is my output.
CC Students:
Alex Kong 3.8 Choice 1
Damian Koh 3.7 Choice 1
Matt Wiliiams 3.3 Choice 1
Irfan Muhaimin 3.3 Choice 1
Muru Arun 3.9 Choice 1
This is the code I have so far.
void sortCC(){
ifstream File;
File.open("DSA.txt");
while (File.good()) {
string Name;
string GPA;
string First;
string Second;
string Third;
getline(File, First, ',');
getline(File, Second, ',');
getline(File, Third, ',');
getline(File, Name, ',');
getline(File, GPA, '\n');
vector <string> v;
v.push_back(First);
v.push_back(Second);
v.push_back(Third);
v.push_back(Name);
v.push_back(GPA);
if (First == "CC"){
cout << Name << " " << GPA << " " << "Choice 1" << '\n';
}
}
}
This is the kind of output I need.
Muru Arun 3.9 Choice 1
Alex Kong 3.8 Choice 1
Hakim, this isn't going to be fully trivial, but you'll learn a lot doing it. I'm going to outline what you need to do. You need to work on this as individual pieces.
First, you need to create a class that holds the individual records of data. The class would look something like this:
class Student {
public:
std::string first;
std::string second;
std::string third;
std::string name;
double gpa;
};
That's part one. Part two is to get data into it. Now, that's going to be from your input file, but for testing purposes, let's do it manually.
std::vector<Student> students;
Student firstStudent{"a", "b", "c", "First", 3.5};
students.push_back(firstStudent);
... Repeat until you have several of them.
Then you want a method that prints them, something like this:
std::ostream & operator<<(std::ostream &output, std::vector<Student> vec) {
for (const Student &student: vec) {
output << "Student: " << student.name << " GPA: " << student.gpa << endl;
}
return output;
}
You can call that method like this (for instance);
std::cout << students;
Try all that. It might take you a bit to get it right. Once you can create an array with sample data and print it out, you have only two more parts.
First, instead of hard-coding data, you'll need to read it from your input. You already kind of know how to do that. I think between what you know and the code above, you can figure this out.
Last, you have to sort it. Sorting is a little tricky. So I'm going to give you the line of code that will do it then explain how it works.
#include <algorithm> // Do this at the top of your .cpp
std::sort(students.begin(), students.end(),
[](const Student &first, const Student &second) {
return first.gpa > second.gpa;
});
There's a lot going on here. I'll explain it in parts.
std::sort() is part of the standard C++ library. It can sort based on natural order (which is great for numbers or strings), or you can pass in what's called a Comparator. We're doing it the second way.
You have to pass it the range of what you're sorting. (Unless you're on C++20, but you probably aren't.) That's what the students.begin() and students.end() part is -- we're telling it to sort the entire vector.
Finally, the comparator I've given you is called a lambda. You could also have written a comparison method and referenced it, but I do it this way. This is basically saying, "Here's the method that returns true if they're in the right order".
The syntax is weird, I know.
At this point, you just have to put it all together.
With this much help, it'll take you about another hour.

cash reg loading individual words from each line into the different struct members

I have this homework assignment that has me a little lost. I have been working on this assignment writing my code, erasing, rewrite, repeat etc. Here are the instructions:
Step (1)
Associated with this assignment is a data file called prices.txt. It contains details of the prices for items in a
grocery store. The first column is the barcode for the item (http://en.wikipedia.org/wiki/Barcode) the
second column, starting in position 11, is the product name, and the third column, starting in position 37 is
the product price.
Write a function with the signature int loadData() which prompts the user for the location of the data file
on disk and then loads the data from the file into an array of elements. Each element of the array should be
a struct declared as follows:
struct Item {
string code;
string name;
double price;
};
The array itself should be called items and should be declared at file scope as follows:
const int MAX_ITEMS = 100;
Item items[MAX_ITEMS];
Notice that the array has size 100, so you can assume the number of items in the data file is less than 100.
Therefore, when loadData has finished loading the data into the array some elements in the array will be unused. The function loadData returns the number of items actually loaded into the array.
I am unsure on how to attempt the function described in the instructions. My code:
int loadData () {
string inputFileName;
ifstream inputFile;
int numOfItems = 0;
cout << "Please input the name of the backup file: ";
cin >> inputFileName; //read user input for the location of the
//backup file
inputFile.open(inputFileName.c_str()); //open specified document
if (!inputFile.is_open()) { //If the file does not open the errormsg
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
//Not sure where to start. I know I need to get each element from
//each newline.
return numOfItems;
}
I wanted to figure this out on my own but that isn't gonna happen. So if I could just get some hints or even suggested pools of knowledge that would guide me or even give me an idea of where to start.
addition: input file:
10001 Apples (bunch) 4.59
10002 Bananas (bunch) 4.99
10003 Pears (bunch) 5.49
20001 White bread (loaf) 2.69
20002 Brown bread (loaf) 2.89
20003 English Muffins (bag) 3.99
30001 Sugar (5 lb bag) 3.99
30002 Tea (box) 4.29
30003 Folger's Coffee (Can) 13.29
This is the entire input file.
Since the input file seems to be using fixed-width columns, it's actually very easy to extract the fields. Just read one line at a time, and for each line get each element as a sub-string, and put into the structure members. And there are functions to convert strings to floating-point values as well.
Don't worry about the possible leading or trailing spaces, there are ways of trimming that.

Storing data from a text file in an array of structures C++

I am attempting to read data from a text file into an array of structures. The first iteration of the for-loop reads and displays everything correctly until it reaches the Boolean value, and every iteration after that does not display as expected. Is the bool value at the end causing the entire rest of the file to be read incorrectly? Or perhaps an issue stemming from getline?
int main()
{
groceryProduct inventoryDatabase[25];
ifstream fin("inventory.txt");
if (!fin)
{
cout << "File could not be located.";
}
string itemName;
for (int index = 0; index < 25; index++)
{
getline(fin, inventoryDatabase[index].itemName, '\n');
fin >> inventoryDatabase[index].itemNumber;
fin >> inventoryDatabase[index].itemPrice;
fin >> inventoryDatabase[index].membershipPrice;
fin >> inventoryDatabase[index].payByWeight;
cout << inventoryDatabase[index].itemName << endl;
cout << inventoryDatabase[index].itemNumber << endl;
cout << inventoryDatabase[index].itemPrice << endl;
cout << inventoryDatabase[index].membershipPrice << endl;
cout << inventoryDatabase[index].payByWeight << endl;
}
return 0;
};
The structure:
struct groceryProduct
{
double itemPrice;
double membershipPrice;
double itemWeight;
int itemQuantity;
string itemNumber;
string itemName;
bool payByWeight;
};
The output:
Apple
P0000
0.85
0.8
204 (expected output of 'false' instead of 204)
Output for every iteration of loop after first iteration:
-9.25596e+61
-9.25596e+61
204
Thank you, and please let me know if you require any more information.
File:
Apple
P0000
.85
.80
false
Orange
P0001
.95
.85
false
Lemon
P0002
.65
.60
false
You need to tell your stream that the bool values are text with
fin >> boolalpha >> inventoryDatabase[index].payByWeight
You're seeing garbage data after the first bool input because failbit gets set in the stream and no further inputs will work until it is reset. This results in you array's data staying uninitialized.
Here are a couple of things I see that may be causing your problem.
1) An array is not "magically filled" with data. You have an uninitialized array, meaning that the data inside of it does not yet exist. At all.
What you have to do to remedy this is to add a new instance of the struct to the array at the start of each loop iteration.
How'd I spot that? Good rule of thumb: if it's weird, it's memory-related. Make sure you've initialized everything.
2) I've seen weird things happen when you use getline and << next to each other. Is there a particular reason you are using getline over <<?
(I would need to re-research how to work around that weirdness. I used to hit it a lot in my C++ class way back when.)
3) What 1201ProgramAlarm said is absolutely correct.
Side note: Do NOT get into the habit of throwing double around because "I want to be able to arbitrarily throw a large value in there." It's a bad habit that wastes space, as double is twice as large as float.
Learn the difference between float and double - you will almost never need double outside of scientific situations, because it is for numbers with a LOT of decimal places. (That's oversimplifying it.) If you're using double over float all the time, you're using twice the memory you need - 32 bits per variable extra, in fact. It adds up. (And people wonder why modern programs need 8GB of RAM to do the same thing as their 100MB-RAM-using predecessors...)
Prices always have two (rarely three) decimal places, so float should fit that perfectly in all cases. Same with weights.

(C++) - Associating strings with values read in from a file

I am trying to get a value associate with a string inside a file called invoice1.txt
invoice1.txt
hammer#10.00
saw#20.00
So for example, when I lookup "hammer" I would like the expression to evaluate to 10.00.
My code so far
string search;
ifstream inFile;
string line;
double price;
inFile.open("invoice1.txt");
if(!inFile)
{
cout << "Unable to open file" << endl;
return 0;
}
else
{
int pos;
while(inFile.good())
{
getline(inFile,line);
pos=line.find(search);
if(pos!=string::npos)
{
cout<<"The item "<<search<<" costs: "// code to get the price
}
}
}
system("pause");
This is the output I am aiming for:
The item hammer costs: 10.00
The summerise, my question is:
How can I associate values with one another that are read in from a file, so I can get a price for an item without having to reparse the file and find it again?
This is what std::map is for.
What you want to do is break your problem down into multiple stages. Here is a simple set of steps that should help you (there are better ways, but I'm trying to keep things simple here).
I've added some lines to explain how to use std::map, in case you're not familiar.
Read the file line by line.
For each line that is read in, get the value after the '#' character.
Add the value to the map, using the string before '#' as the key...
priceMap[key] = price; // for example, this might evaluate to: myMap["hammer"] = 10.00
When you want to use the value, simple give the map you're key.
std::cout << priceMap["hammer"];
What do you search in line from file? You have to search for character # and split your string into two parts.
getline(inFile,line);
pos=line.find('#');
if(pos!=string::npos)
cout<<"The item "<<line.substr(0,pos)<<" costs: " << line.substr(pos+1,line.size()-1) << endl;// code to get the price
You can save item name and price in different variables if you want. If you want to do something more with a string, read this for further instructions.

read in values and store in list in c++

i have a text file with data like the following:
name
weight
groupcode
name
weight
groupcode
name
weight
groupcode
now i want write the data of all persons into a output file till the maximum weight of 10000 kg is reached.
currently i have this:
void loadData(){
ifstream readFile( "inFile.txt" );
if( !readFile.is_open() )
{
cout << "Cannot open file" << endl;
}
else
{
cout << "Open file" << endl;
}
char row[30]; // max length of a value
while(readFile.getline (row, 50))
{
cout << row << endl;
// how can i store the data into a list and also calculating the total weight?
}
readFile.close();
}
i work with visual studio 2010 professional!
because i am a c++ beginner there could be is a better way! i am open for any idea's and suggestions
thanks in advance!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
struct entry
{
entry()
: weight()
{ }
std::string name;
int weight; // kg
std::string group_code;
};
// content of data.txt
// (without leading space)
//
// John
// 80
// Wrestler
//
// Joe
// 75
// Cowboy
int main()
{
std::ifstream stream("data.txt");
if (stream)
{
std::vector<entry> entries;
const int limit_total_weight = 10000; // kg
int total_weight = 0; // kg
entry current;
while (std::getline(stream, current.name) &&
stream >> current.weight &&
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n') && // skip the rest of the line containing the weight
std::getline(stream, current.group_code))
{
entries.push_back(current);
total_weight += current.weight;
if (total_weight > limit_total_weight)
{
break;
}
// ignore empty line
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
else
{
std::cerr << "could not open the file" << std::endl;
}
}
Edit: Since you wannt to write the entries to a file, just stream out the entries instead of storing them in the vector. And of course you could overload the operator >> and operator << for the entry type.
Well here's a clue. Do you see the mismatch between your code and your problem description? In your problem description you have the data in groups of four lines, name, weight, groupcode, and a blank line. But in your code you only read one line each time round your loop, you should read four lines each time round your loop. So something like this
char name[30];
char weight[30];
char groupcode[30];
char blank[30];
while (readFile.getline (name, 30) &&
readFile.getline (weight, 30) &&
readFile.getline (groupcode, 30) &&
readFile.getline (blank, 30))
{
// now do something with name, weight and groupcode
}
Not perfect by a long way, but hopefully will get you started on the right track. Remember the structure of your code should match the structure of your problem description.
Have two file pointers, try reading input file and keep writing to o/p file. Meanwhile have a counter and keep incrementing with weight. When weight >= 10k, break the loop. By then you will have required data in o/p file.
Use this link for list of I/O APIs:
http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx
If you want to struggle through things to build a working program on your own, read this. If you'd rather learn by example and study a strong example of C++ input/output, I'd definitely suggest poring over Simon's code.
First things first: You created a row buffer with 30 characters when you wrote, "char row[30];"
In the next line, you should change the readFile.getline(row, 50) call to readFile.getline(row, 30). Otherwise, it will try to read in 50 characters, and if someone has a name longer than 30, the memory past the buffer will become corrupted. So, that's a no-no. ;)
If you want to learn C++, I would strongly suggest that you use the standard library for I/O rather than the Microsoft-specific libraries that rplusg suggested. You're on the right track with ifstream and getline. If you want to learn pure C++, Simon has the right idea in his comment about switching out the character array for an std::string.
Anyway, john gave good advice about structuring your program around the problem description. As he said, you will want to read four lines with every iteration of the loop. When you read the weight line, you will want to find a way to get numerical output from it (if you're sticking with the character array, try http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/, or try http://www.cplusplus.com/reference/clibrary/cstdlib/atof/ for non-whole numbers). Then you can add that to a running weight total. Each iteration, output data to a file as required, and once your weight total >= 10000, that's when you know to break out of the loop.
However, you might not want to use getline inside of your while condition at all: Since you have to use getline four times each loop iteration, you would either have to use something similar to Simon's code or store your results in four separate buffers if you did it that way (otherwise, you won't have time to read the weight and print out the line before the next line is read in!).
Instead, you can also structure the loop to be while(total <= 10000) or something similar. In that case, you can use four sets of if(readFile.getline(row, 30)) inside of the loop, and you'll be able to read in the weight and print things out in between each set. The loop will end automatically after the iteration that pushes the total weight over 10000...but you should also break out of it if you reach the end of the file, or you'll be stuck in a loop for all eternity. :p
Good luck!