C++ Making a vector from .txt file data - c++

I'm working on another school project, in part of which I need to take the data from a .txt file and convert it to a mixed type vector... that contains two integers and a string. I've tried various ways of doing it, and I have it down to where the .txt file is inputted, and hopefully sent to vectors. My difficulty comes in when I try to do stuff with the vectors. My code segment is as follows (I'll explain what things are for with comments):
bool ReadPeopleFromFile(int argc, char* argv[], vector<Person> &people) {
Person tmpPrsn;
int tmpAge;
string tmpGender;
int tmpAnualIncome;
ifstream PeopleFile("dev_people.txt"); // Try to open file
if (!PeopleFile.is_open()) {
cout << "Could not open file.\n";
return true; // indicates error
}
cout << "Starting" << endl;
while (!PeopleFile.eof()) {
PeopleFile >> tmpAge;
PeopleFile >> tmpGender;
PeopleFile >> tmpAnualIncome;
tmpPrsn.SetData(tmpAge, tmpGender, tmpAnualIncome);
tmpPrsn.Print();
people.push_back(tmpPrsn); // Need to look at this!!!
}
PeopleFile.close();
cout << "Finished reading file." << endl;
return false;
}
//I have a function that gets the user input... I took it out for this post.
vector<Person> ptntlCstmrs;
// Return people within the given age range.
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int AgelowerRange, int AgeupperRange, string DesiredGender, int YIlowerRange, int YIupperRange) {
unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
vector<Person> pplInRange;
int age = 0;
string gender = "";
int yearlyIncome = 0;
for (i = 0; i < ppl.size(); ++i) {
for (j = 0; j < ppl.size(); ++j) {
for (k = 0; k < ppl.size(); ++k) {
age = ppl.at(i).GetAge();
gender = ppl.at(j).GetGender();
yearlyIncome = ppl.at(k).GetYearlyIncome();
if ((age >= AgelowerRange) && (age <= AgeupperRange) && (gender == DesiredGender || gender == "Any") && (yearlyIncome >= YIlowerRange) && (yearlyIncome <= YIupperRange)) {
ptntlCstmrs.push_back(ppl.at(i));
}
}
} // I know this section is messed up... I can't figure out how to get this part to work. What I'm trying to do is take the input, and filter it based on the user-inputted criteria. Nothing that I have done has worked.
}
return pplInRange;
}
int main(int argc, char* argv[]) {
vector<Person> ptntlCstmrs;
bool hadError = false;
int ageLowerRange = 0;
int ageUpperRange = 0;
string desiredGender = "";
int yearlyIncomeLowerRange = 0;
int yearlyIncomeUpperRange = 0;
hadError = ReadPeopleFromFile(argc, argv, ptntlCstmrs);
if (hadError) {
return 1; // indicates error
}
GetUserInput(ageLowerRange, ageUpperRange, desiredGender, yearlyIncomeLowerRange, yearlyIncomeUpperRange);
ptntlCstmrs = GetPeopleWithQualifyingCharacteristics(ptntlCstmrs, ageLowerRange, ageUpperRange, desiredGender, yearlyIncomeLowerRange, yearlyIncomeUpperRange);
cout << "\nNumber of potential customers = " << ptntlCstmrs.size() << endl;
}
I included a bunch of this stuff just in case some of my references are off, but I don't think so. It also tells you what I'm working with. I would like help figuring out how to get the criteria to actually sort the vectors, and then print out how many of those vectors are going to work with the user inputted data.
Thanks in advance!

The credit really goes to #PaulMcKenzie . The problem with the above code is in the following section:
Return people within the given age range.
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int AgelowerRange, int AgeupperRange, string DesiredGender, int YIlowerRange, int YIupperRange) {
unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
vector<Person> pplInRange;
int age = 0;
string gender = "";
int yearlyIncome = 0;
for (i = 0; i < ppl.size(); ++i) {
for (j = 0; j < ppl.size(); ++j) {
for (k = 0; k < ppl.size(); ++k) {
age = ppl.at(i).GetAge();
gender = ppl.at(j).GetGender();
yearlyIncome = ppl.at(k).GetYearlyIncome();
if ((age >= AgelowerRange) && (age <= AgeupperRange) && (gender == DesiredGender || gender == "Any") && (yearlyIncome >= YIlowerRange) && (yearlyIncome <= YIupperRange)) {
ptntlCstmrs.push_back(ppl.at(i));
}
}
} // I know this section is messed up... I can't figure out how to get this part to work. What I'm trying to do is take the input, and filter it based on the user-inputted criteria. Nothing that I have done has worked.
}
return pplInRange;
which needs to be changed to the following:
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int Agelow, int Ageup, string DesGen, int YIlow, int YIup) {
unsigned int i = 0;
int age = 0;
string gender = "";
int yearlyIncome = 0;
ifstream PeopleFile("dev_people.txt");
while (PeopleFile >> age >> gender >> yearlyIncome);
vector<Person> pplInRange;
for (i = 0; i < ppl.size(); ++i) {
age = ppl.at(i).GetAge();
gender = ppl.at(i).GetGender();
yearlyIncome = ppl.at(i).GetYearlyIncome();
if ((age >= Agelow) && (age <= Ageup) && (DesGen == gender || DesGen == "Any") && (yearlyIncome >= YIlow) && (yearlyIncome <= YIup)) {
pplInRange.push_back(ppl.at(i));
}
}
return pplInRange;
}
Now it works fine. Thanks Paul!

My initial thoughts are that you aren't collecting user input correctly. You send your variables that determine whether or not a Person object is a potential customer off into another function.
By default C++ passes parameters by value -- meaning that when a parameter is passed into a function, a copy of said parameter is made and used throughout that function. When the function comes to a close, the edited parameter is then disposed of and all changes / edits are lost. If you want to grab user input from another method, and have said input saved, make sure to pass your parameters by reference.
Passing by reference essentially tells the machine where that specific parameter is located in memory and allows the program to directly access that piece of memory as opposed to making a copy of the parameter when executing your function. This in turn makes any changes made to parameters permanent!
Hope this helps!

Related

Trying to compare a randomly generated array to user filled array

I am currently working on a project to create a game of Mastermind. The user must input 3 colors and the program will compare which are the correct color and in the proper place,which are the correct color but in the wrong place, and which are the wrong color. All seems well except I'm unable to properly compare the info within the randomly generated array with the user filled array. I'm sure I'd have to use a loop to accomplish this.
-Things that I feel may be the issue:
*The information within both arrays are not being stored properly.
*conflicting types.
void gameS() {
int close, right, attempts = 0;
string choice[3],code; // holds user input
const int arrySize = 5;
srand(time(0)); //random numbers
string ranColor[arrySize] = { "R", "B", "W", "Y", "G" }; // possible color options
for (int i = 0; i < arrySize - 2; i++) //generat random colors
{
int rcolor = rand() % arrySize;
code = ranColor[rcolor];
cout << code << endl;
}
while (attempts < 10) {
cout << "You should input your color choices below. Your options are - R : Red, B : Blue, W : White, Y : Yellow, G : Green.\n" << "Please choose 3 for your " << attempts+1 << " attempt.\n" << "******************************************************\n\n";
cout << "\n\nPlease enter the color of the first peg: "; //user input to choice array spot : 1
cin >> choice[0];
cout << "\nPlease enter the color of the second peg: "; //user input to choice array spot : 2
cin >> choice[1];
cout << "\nPlease enter the color of the third peg: "; //user input to choice array spot : 3
cin >> choice[2];
attempts++; // proceeds to next turn/attempt
//checks for correct colors in correct places
for (int i = 0; i < 3; i++)
{
if (code == choice[i])
{
right++;
choice[i] = "X";
}
}
//Determin the number of right colors in the wrong place
for (int i = 0; i < 3; i++)
{
for (int y = 0; y < 3; y++) {
if (code[i] == choice[y]) {
close++;
choice[i] = "Y";
}
}
}
}
}
I receive errors for the following lines:
*'argument':conversion from tim_t to unsigned in' possible loss of data
srand(time(0));
*Using uninitialized memory 'right'
`if (code == choice[i])
{
right++;
choice[i] = "X";
}`
*Using uninitialized memory 'close'
`for (int i = 0; i < 3; i++)
{
for (int y = 0; y < 3; y++) {
if (code == choice[y])
{
close++;
choice[i] = "Y";
}
}
}
*no operator "==" matches these operands.
*Binary '==':o global operator found which takes type 'std::string'(or there is no acceptable conversion)
`for (int y = 0; y < 3; y++) {
if (code[i] == choice[y])
{
close++;
choice[i] = "Y";
}`
Any tips would be appreciated.
From what I can see there is some initialization problems.
First
int close, right, attempts = 0;
Will leave close and right empty, simply initialize them properly
int close = 0, right = 0, attempts = 0;
It looks like you want to use code as an array, but the problem is, it is not initialized as an array
string choice[3],code; // holds user input
A quick fix is
string choice[3],code[3]; // holds user input
Now, where you generate the answer, there is another syntax problem
code = ranColor[rcolor];
since you want to store the answer in the code array, an index must be specified, in this case
code[i] = ranColor[rcolor];
The final problem lies in
//checks for correct colors in correct places
for (int i = 0; i < 3; i++)
{
if (code == choice[i])
{
right++;
choice[i] = "X";
}
}
Since code is an array now, simply change the condition statement to
if (code[i] == choice[i])

Why is my array always giving a true answer?

My code here says that all values are true even if they aren't in the array. What am I doing wrong? For instance, I could input Chicago, and it will say "City found." I have tried to change the order around and change the "if(foundIt) to if(foundIt = true). It will still do the same.
// MichiganCities.cpp - This program prints a message for invalid cities in Michigan.
// Input: Interactive
// Output: Error message or nothing
#include <iostream>
#include <string>
using namespace std;
int main()
{
// Declare variables
string inCity; // name of city to look up in array
const int NUM_CITIES = 10;
// Initialized array of cities
string citiesInMichigan[] = {"Acme", "Albion", "Detroit", "Watervliet", "Coloma", "Saginaw", "Richland", "Glenn", "Midland", "Brooklyn"};
bool foundIt = false; // Flag variable
int x; // Loop control variable
// Get user input
cout << "Enter name of city: ";
cin >> inCity;
// Write your loop here
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
// Write your test statement here to see if there is
// a match. Set the flag to true if city is found.
if (foundIt)
cout << "City found." << endl;
else cout << "Not a city in Michigan." << endl;
// Test to see if city was not found to determine if
// "Not a city in Michigan" message should be printed.
return 0;
} // End of main()
This loop
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
does not make sense. There is used an assignment in the if statement of the control variable i to the variable x.
if (x = i)
It seems you mean at least
for(int i = 0; !foundIt && i < NUM_CITIES; i++){
if ( inCity == citiesInMichigan[i] )
foundIt = true;
}
If you need the index of the found city then the loop can look like
size_t i = 0;
while ( i < NUM_CITIES && inCity != citiesInMichigan[i] ) i++;
if ( i != NUM_CITIES )
{
// the city is found at position i
}
else
{
// the sity is not found
}

What's wrong with my dynamic programming algorithm with memoization?

*Sorry about my poor English. If there is anything that you don't understand, please tell me so that I can give you more information that 'make sence'.
**This is first time asking question in Stackoverflow. I've searched some rules for asking questions correctly here, but there should be something I missed. I welcome all feedback.
I'm currently solving algorithm problems to improve my skill, and I'm struggling with one question for three days. This question is from https://algospot.com/judge/problem/read/RESTORE , but since this page is in KOREAN, I tried to translate it in English.
Question
If there are 'k' pieces of partial strings given, calculate shortest string that includes all partial strings.
All strings consist only lowercase alphabets.
If there are more than 1 result strings that satisfy all conditions with same length, choose any string.
Input
In the first line of input, number of test case 'C'(C<=50) is given.
For each test case, number of partial string 'k'(1<=k<=15) is given in the first line, and in next k lines partial strings are given.
Length of partial string is between 1 to 40.
Output
For each testcase, print shortest string that includes all partial strings.
Sample Input
3
3
geo
oji
jing
2
world
hello
3
abrac
cadabra
dabr
Sample Output
geojing
helloworld
cadabrac
And here is my code. My code seems to work perfect with Sample Inputs, and when I made test inputs for my own and tested, everything worked fine. But when I submit this code, they say my code is 'wrong'.
Please tell me what is wrong with my code. You don't need to tell me whole fixed code, I just need sample inputs that causes error with my code. Added code description to make my code easier to understand.
Code Description
Saved all input partial strings in vector 'stringParts'.
Saved current shortest string result in global variable 'answer'.
Used 'cache' array for memoization - to skip repeated function call.
Algorithm I designed to solve this problem is divided into two function -
restore() & eraseOverlapped().
restore() function calculates shortest string that includes all partial strings in 'stringParts'.
Result of resotre() is saved in 'answer'.
For restore(), there are three parameters - 'curString', 'selected' and 'last'.
'curString' stands for currently selected and overlapped string result.
'selected' stands for currently selected elements of 'stringParts'. Used bitmask to make my algorithm concise.
'last' stands for last selected element of 'stringParts' for making 'curString'.
eraseOverlapped() function does preprocessing - it deletes elements of 'stringParts' that can be completly included to other elements before executing restore().
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
string answer; // save shortest result string
vector<string> stringParts;
bool cache[MAX + 1][(1 << MAX) + 1]; //[last selected string][set of selected strings in Bitmask]
void restore(string curString, int selected=0, int last=0) {
//base case 1
if (selected == (1 << k) - 1) {
if (answer.empty() || curString.length() < answer.length())
answer = curString;
return;
}
//base case 2 - memoization
bool& ret = cache[last][selected];
if (ret != false) return;
for (int next = 0; next < k; next++) {
string checkStr = stringParts[next];
if (selected & (1 << next)) continue;
if (curString.empty())
restore(checkStr, selected + (1 << next), next + 1);
else {
int check = false;
//count max overlapping area of two strings and overlap two strings.
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size()-i, i) == checkStr.substr(0, i)) {
restore(curString + checkStr.substr(i, checkStr.length()-i), selected + (1 << next), next + 1);
check = true;
break;
}
}
if (!check) { // if there aren't any overlapping area
restore(curString + checkStr, selected + (1 << next), next + 1);
}
}
}
ret = true;
}
//check if there are strings that can be completely included by other strings, and delete that string.
void eraseOverlapped() {
//arranging string vector in ascending order of string length
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
//deleting included strings
vector<string>::iterator iter;
for (int i = 0; i < vectorLen-1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C; // testcase
for (int testCase = 0; testCase < C; testCase++) {
cin >> k; // number of partial strings
memset(cache, false, sizeof(cache)); // initializing cache to false
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
eraseOverlapped();
k = stringParts.size();
restore("");
cout << answer << endl;
answer.clear();
stringParts.clear();
}
}
After determining which string-parts can be removed from the list since they are contained in other string-parts, one way to model this problem might be as the "taxicab ripoff problem" problem (or Max TSP), where each potential length reduction by overlap is given a positive weight. Considering that the input size in the question is very small, it seems likely that they expect a near brute-force solution, with possibly some heuristic and backtracking or other form of memoization.
Thanks Everyone who tried to help me solve this problem. I actually solved this problem with few changes on my previous algorithm. These are main changes.
In my previous algorithm I saved result of restore() in global variable 'answer' since restore() didn't return anything, but in new algorithm since restore() returns mid-process answer string I no longer need to use 'answer'.
Used string type cache instead of bool type cache. I found out using bool cache for memoization in this algorithm was useless.
Deleted 'curString' parameter from restore(). Since what we only need during recursive call is one previously selected partial string, 'last' can replace role of 'curString'.
CODE
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
vector<string> stringParts;
string cache[MAX + 1][(1 << MAX) + 1];
string restore(int selected = 0, int last = -1) {
if (selected == (1 << k) - 1) {
return stringParts[last];
}
if (last == -1) {
string ret = "";
for (int next = 0; next < k; next++) {
string resultStr = restore(selected + (1 << next), next);
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
string& ret = cache[last][selected];
if (!ret.empty()) {
cout << "cache used in [" << last << "][" << selected << "]" << endl;
return ret;
}
string curString = stringParts[last];
for (int next = 0; next < k; next++) {
if (selected & (1 << next)) continue;
string checkStr = restore(selected + (1 << next), next);
int check = false;
string resultStr;
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size() - i, i) == checkStr.substr(0, i)) {
resultStr = curString + checkStr.substr(i, checkStr.length() - i);
check = true;
break;
}
}
if (!check)
resultStr = curString + checkStr;
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
void EraseOverlapped() {
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
vector<string>::iterator iter;
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C;
for (int testCase = 0; testCase < C; testCase++) {
cin >> k;
for (int i = 0; i < MAX + 1; i++) {
for (int j = 0; j < (1 << MAX) + 1; j++)
cache[i][j] = "";
}
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
EraseOverlapped();
k = stringParts.size();
string resultStr = restore();
cout << resultStr << endl;
stringParts.clear();
}
}
This algorithm is much slower than the 'ideal' algorithm that the book I'm studying suggests, but it was fast enough to pass this question's time limit.

C++ Counting Specific Counters in Character Array from File

I'm trying to count the number of specific characters from a file. The problem I have run into is that the output is a huge number that does not match up with the amount of each letter in the file.
RainOrShine.txt
RRCSSSCSCRRRCSSSCSSRSCCRCRRCSS
SSSCCSSSCCSSSCCSSSCRCRCCSSSSSS
SSSSCSSSCSSSCRRCCCSSSSSCSSSSCS
#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
string filelocation = "C:/Users/erizj/OneDrive/Documents/RainOrShine.txt";
ifstream textfile;
textfile.open(filelocation.c_str());
char weather[3][30];
int countR,countC,countS = 0;
if (!textfile)
{
cout << "Error opening the file.";
return 0;
}
else
{ // Read weather data in from file
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 30; col++)
{
textfile >> weather[row][col];
if(weather[row][col]=='R'){
countR++;
}
if(weather[row][col]=='C'){
countC++;
}
if(weather[row][col]=='S'){
countS++;
}
}
}
}
cout<<"Rainy Days during 3-Month Period: "<<countR<<endl;
cout<<"Cloudy Days during 3-Month Period: "<<countC<<endl;
cout<<"Sunny Days during 3-Month Period: "<<countS<<endl;
//cout<<"Rainy Days in June: "<<
textfile.close();
return 0;
}
Output:
Rainy Days during 3-Month Period: 4201688
Cloudy Days during 3-Month Period: 6356911
Sunny Days during 3-Month Period: 50
Does it have something to do with the counter that I set up? Thank in advance.
int countR,countC,countS = 0;
initializes countS but leaves countR and countC uninitialized.
Your program is assuming that there are a fixed number of rows and columns in the data. This could be a problem.
I suggest a more flexible approach, no assumptions about how the data is organized or the quantity of data.
Let's define a structure for our database. The data can be stored sequentially, but we need the data structure to be dynamic: std::vector.
Now to read in the data before making any analysis:
std::vector<char> database;
std::string text_line; // Easier to read in a lot of data
while (getline(data_file, text_line))
{
std::string::size_type index;
const std::string::size_type length = text_line.length();
for (index = 0; index < length; ++index)
{
const char c = text_line[index];
if ((c == 'R') || (c == 'S') || (c == 'C'))
{
database.push_back(c);
}
}
}
Since the data is read into a database, you can analyze it:
unsigned int duration = 0;
unsigned int rain_quantity = 0;
unsigned int sunny_quantity = 0;
unsigned int cloudy_quantity = 0;
// Set up the duration for the first 30 days
duration = 30;
if (database.size() < 30)
{
duration = database.size();
}
for (unsigned int index = 0; index < duration; ++index)
{
const char c = database[index];
if (c == 'C')
{
++cloudy_quantity;
}
else
{
if (c == 'R')
{
++rain_quantity;
}
else
{
++sunny_quantity;
}
}
}
You can perform other analysis without reading the data from the file.
You need to initialize all of your integer variables separately.
int countR = 0, countS = 0, countT = 0;

c++ binary to decimal converter input to only accept 1 or 0

Hello I am trying to do a programming assignment that converts a binary number to a decimal. The problem states that I have to get the users input as a sting and if there is anything other than a 1 or a 0 in the users input it should give an error message then prompt them to give a new input. I have been trying for a while now and I cant seem to get it right can anyone help me?
so far this is my best attempt it will run every input of the string into a if statement but it only seems to care about the last digit i cant think of a way to make it so if there is a single error it will keep while loop statement as true to keep going.
#include <iostream>
#include <string>
using namespace std;
string a;
int input();
int main()
{
input();
int stop;
cin >> stop;
return 0;
}
int input()
{
int x, count, repeat = 0;
while (repeat == 0)
{
cout << "Enter a string representing a binary number => ";
cin >> a;
count = a.length();
for (x = 0; x < count; x++)
{
if (a[x] >= '0' &&a[x] <= '1')
{
repeat = 1;
}
else
repeat = 0;
}
}
return 0;
}
return 0;
}
Change your for loop as this:
count = a.length();
repeat = 1;
for (x = 0; x < count; x++)
{
if (a[x] != '0' && a[x] != '1')
{
repeat = 0;
break;
}
}
The idea is that repeat is assumed to be 1 at first (so you assume that your input is valid). Later on, if any of your input characters is not a 0 or 1, then you set repeat to 0 and exit the loop (there's no need to keep looking for another character)