How to loop through multiple condition IF statement in C++ - c++

I am a newbie in programming and I wrote a piece of code that works, but I am interested in making it scalable.
The following code checks if a single word from a vector list matches with any of the words in another vector list.
if (words[i] != dislike[0] && words[i] != dislike[1] && words[i] != dislike[2] && words[i] != dislike[3]) //check for disliked words
cout << words[i] << '\n';
As visibile, the code does the job by iterating word by word, so if I were to change the nubmer of words in my second vector list, I will need to add it to the IF statement.
Is there a more optimal solution? I have been trying to figure this out for hours, however I had no luck.
Thanks.
P.S. Below is my full code.
int main()
{
// words we dislike
vector<string>dislike = { "broccoli", "coke", "potatoes", "water" };
//take input from user
vector<string> words;
for (string temp; cin >> temp; ) // read whitespace-separated words
words.push_back(temp); // put into vector
//give output
cout << "Number of words: " << words.size() << '\n';
//sort(words); // DONT sort the words
for (int i = 0; i<words.size(); ++i) //go through your words vector
{
if (i == 0 || words[i - 1] != words[i])//remove repeating words
{
if (words[i] != dislike[0] && words[i] != dislike[1] && words[i] != dislike[2] && words[i] != dislike[3]) //check for dislike
cout << words[i] << '\n';
else
cout << "BlEEP!\n"; //print if word is disliked*/
}
}
return 0;
}

What about this?
Adding another loop for that iterates throught all the dislike vector.
int main()
{
// words we dislike
vector<string>dislike = { "broccoli", "coke", "potatoes", "water" };
//take input from user
vector<string> words;
for (string temp; cin >> temp; ) // read whitespace-separated words
words.push_back(temp); // put into vector
//give output
cout << "Number of words: " << words.size() << '\n';
//sort(words); // DONT sort the words
for (int i = 0; i<words.size(); ++i) //go through your words vector
{
if (i == 0 || words[i - 1] != words[i])//remove repeating words
{
for(int j=0;j<dislike.size();j++)
{
int count = 0;
if (words[i] != dislike[j])count++;
if(count == dislike.size())cout << words[i] << '\n'; //check for dislike
else
cout << "BlEEP!\n"; //print if word is disliked*/
}
}
}
return 0;
}

Related

Given an array of words and a string, how can I count all words in a given string

Given an array of words and a string, I need to count all the words that are present in a given string.
I have split the sentence and included the words in a hash map. However, when I iterate through the string array to check if that word is present, I'm getting an incorrect output. How do I rectify the code?
#include<bits/stdc++.h>
using namespace std;
void countwords(string str,string words[],int n )
{
map<string ,bool > m1; //map
map<string ,bool > ::iterator it;
int i=0,cnt=0;
string temp = " ";
while(i<str.size()) // splitting of sentence into words
{
while(str[i]!=' '&&i<str.size()&&str[i]!='.') // if it doesnt encounter space, add it to temp
{
temp+=str[i];
i++;
}
m1[temp]=true; // insert temp into map
temp=" ";
i++;
}
for(i=0;i<n;i++)
{
if(m1.find(words[i])!=m1.end()&&m1[words[i]]==true) // if word is present in the map increment count & it isn't a duplicate
{
cnt++;
m1[words[i]]=false;
}
}
cout<<cnt;
}
There are some problems with your code.
1- temp = " " , you need to set temp to an empty string or the find() function will not work for it
2- using map, you will have only one instance of a word in map, so you need to keep a count of each word.
Below code counts and prints number of words of a given array, with minimum changes to your code:
void countwords(string str,string words[],int n ){
map<string ,int > m1;
int i=0, cnt=0;
string temp = "";
while(i < str.size())
{
while(str[i]!=' ' && i<str.size() && str[i]!='.')
{
if(str[i]!=' ' && str[i]!='.')
temp+=str[i];
i++;
}
auto iii = m1.find(temp);
int count = 0;
if(iii != m1.end())
count = iii->second;
count+=1;
m1[temp]=count;
temp="";
i++;
}
for(int i=0; i != n; i++)
{
auto found = m1.find(words[i]);
if(found != m1.end())
std::cout << found->first << " " << found->second << std::endl;
else cout << words[i] << " " << "0" << std::endl;
}}

How to end a 2D char array when string is '\0'?

I have a program that queries the user for string inputs that are stored in a 2D char array. The program should stop asking for inputs when 20 strings are entered or when the user hits enter twice.
For some reason no matter what I do, the program will keep displaying all empty strings even though the user hasn't populated them. How can I stop this?
int main()
{
char sentences[20][81] = { '\0' };
cout << "Enter up to 20 sentences - when done, Press ENTER: ";
input(sentences);
for (int i = 0; i < 20; i++)
{
if (sentences[i] == '\0' || sentences[i] == "\n")
break;
else
{
cout << "\nHere is sentence " << i + 1 << ": " << endl << sentences[i] << endl;
menu(sentences[i]);
}
}
cout << "\nPress any key to continue...";
_getch();
return 0;
}
void input(char str[20][81])
{
for (int i = 0; i < 20; i++)
{
cin.getline(str[i], 81, '\n');
if (str[i][0] == '\0')
break;
}
}
There are no error messages, and I expect that the check here
if (sentences[i] == '\0' || sentences[i] == "\n"
break;
should end the program when a blank c-string is encountered, why isn't that happening?
This check here is wrong:
if (sentences[i] == '\0' || sentences[i] == "\n")
You're comparing sentences[i] (a char*) with '\0' (a char). The sentences[i] == "\n" part is entirely wrong - just get rid of that. Your check should look like this:
if (sentences[i][0] == '\0' )
But I would really recommend just using a std::vector<std::string> instead of this multidimensional c-style string construct. You can just use push_back to add a string to the vector and range-based for loop to go through the vector and print its results. You can do this with your input function like this:
void input(std::vector<std::string> &sentences)
{
for (int i = 0; i < 20; i++)
{
std::string s;
std::getline(std::cin, s);
if (s.empty())
break;
sentences.push_back(s);
}
}
And then the main function like that:
int main()
{
std::vector<std::string> sentences;
std::cout << "Enter up to 20 sentences - when done, Press ENTER: " << std::endl;
input(sentences);
for (int i = 0; i < sentences.size(); i++)
std::cout << "Here is sentence " << i + 1 << ": " << std::endl << sentences[i] << std::endl;
std::cout << "Press any key to continue...";
//getch();
return 0;
}
This way you wouldn't even need the hard-coded limit of 20 sentences, you could just remove it and have a while (true) loop instead.

Reading a file with c++ containing chars and numbers

I have a text file containing sort of a graph presentation, as such:
7
{5, 2, 3}, {1,5}, { }, { }, {3}, { }, { }
Now, I know how to read a file and get in into an int
while ((n = myfile.get()) != EOF)
or into a string line by line
getline (myfile,line)
The problem I have, is that with both of these options I can't really seem to compare every character I extract and check if it's a number or a "," or "{" or "}".
Is there a simple way of doing that? I've been banging my head with this for hours since yesterday. I've tried some isdigit and casting, but that didn't work for me as well and really complicated stuff.
The easiest solution, I think, would be to get your hands dirty a bit, by reading the file char by char. I suggest you store the sets in a vector of vectors of ints (visualize it like a 2D array, a matrix, if you like).
If the i-th set is empty, then the i-th vector will be empty too.
In the loop in which you will parse the characters, you will skip the opening curly braces and commas. You will do similarly for the closing curly braces, except from the fact that you would need to update an index, which will help us update the index-th vector.
When we actually read a digit, then you can convert a char to an int.
Complete example:
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main(void) {
char ch;
fstream fin("test.txt", fstream::in);
if(!fin) {
cerr << "Something is wrong...! Exiting..." << endl;
return -1;
}
int N; // number of sets
fin >> N;
vector<vector<int> > v;
v.resize(N);
int i = 0;
while (fin >> ch) {
//cout << ch << endl;
if(ch == '{' || ch == ',')
continue;
if(ch == '}') {
i++;
continue;
}
v[i].push_back(ch - '0');
}
if(i == N) {
cout << "Parsing the file completed successfully." << endl;
} else {
cout << "Parsed only " << i << " sets, instead of " << N << endl;
}
for(size_t i = 0; i < v.size(); ++i) {
if(v[i].size() == 0)
cout << i + 1 << "-th set is empty\n";
else {
for(size_t j = 0; j < v[i].size(); ++j)
cout << v[i][j] << " ";
cout << endl;
}
}
return 0;
}
Output:
gsamaras#aristotelis:/Storage/homes/gsamaras$ g++ main.cpp
gsamaras#aristotelis:/Storage/homes/gsamaras$ ./a.out
Parsing the file completed successfully.
5 2 3
1 5
3-th set is empty
4-th set is empty
3
6-th set is empty
7-th set is empty
Important note: This should serve as a starting point, since it won't treat numbers that have more than one digits. In this case, you will to read up to the comma, or the closing curly brace, to make sure that you read all the digits of the numbers, then convert from string to integer, and then store it in the corresponding vector.
Its better to read character by character as follows:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
string line;
int lineNum = 0;
ifstream myfile ("file.txt");
if (myfile.is_open())
{
while ( getline (myfile, line) )
{
// Identifying the type of charcter
char a;
cout << "Line Number " << ++lineNum << ": ";
for(int i = 0; i < line.length(); i++)
{
a = line[i];
cout << "\n\t" << a;
if((a >= 32 && a <= 47) || (a >= 58 && a <= 64) || (a >= 91 && a <= 96) || (a >= 123 && a <= 126))
{
cout << "\t(This character is either a Punctuation or arithmetic mark.)";
// If you don't want to porcess these character, then you may 'continue' to the next sub string
}
else if(a >= 48 && a <= 57)
{
cout << "\t(This character is a number.)";
// If you want to change the number ot int, you can use atoi or stoi
}
else if(a >= 65 && a <= 90)
cout << "\t(Capital letter)";
else if(a >= 97 && a <= 122)
cout << "\t(Small letter)";
}
cout<<endl;
}
myfile.close();
}
else
cout << "Unable to open file";
return 0;
}
I hop this helps.

How to parse a string and ignore whitespace?

int line = 0;
string teststring = " ";
string stringarray[100];
while (codeFile.good())
{
getline(codeFile, teststring, ' ');
if(teststring!="" && teststring[0]!='\n' && teststring[0] != 9 && teststring[0] != 10 && teststring[0] != 32 && teststring[0]!=' '
&& teststring!=" " && teststring!=" ")
{
stringarray[line]=teststring; // still stores whitespace :(
cout << stringarray[line] << endl;
line++;
}
}
Hello, I am going through a text file and trying to store each string inside an element of an array but, am having problems with elements storing completely white space.
I have just solve a similar problem, how about this code:
while (codeFile.good())
{
getline(codeFile, teststring);
for(size_t idx = 0; idx < teststring.size(); i++) {
size_t start = idx;
while (teststring[i] != ' ') {
idx++;
}
stringarray[line] = teststring.substr(start, idx - start);
cout << stringarray[line] << endl;
line++;
}
}
Ignoring all the white spaces is exactly what operator>> does.
Your snippet can be rewritten as:
// ...
std::string word;
std::vector<std::string> words;
while ( codeFile >> word )
{
if ( word.empty() ) continue;
std::cout << word << '\n';
words.push_back(std::move(word));
}

Getting errors when I compare elements in two vectors - am I doing something wrong?

The task is pretty simple: create a program that will tell the user if a sentence he or she enters is the same backwards and forwards (in terms of words used, not spelling). For example, "I am that am I" (please ignore how grammatically nonsensical this may be). So I decided to create two string vectors - one that would store the original sentence, and another that would be the sentence reversed. The elements of each vector would be strings containing the words of the sentence, e.g ["I", "am", "that", "am", I"], excluding any spaces in the string.
I'm stuck in a preliminary state of solving this problem - comparing the elements of these two vectors. Here's my code below (note that sentence is the first vector, and reverseString is the second vector, containing the elements in reverse order):
for (int i = 0; i < sentence.size(); i++) {
// The below output is for debugging purposes
cout << "The index is " << i
<< " and the original string at this location is " << sentence[i]
<< " and the reverse string is " << reverseString[i] << endl;
if (sentence[i] == reverseString[i]) {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "A match!" << endl;
} else {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "Not a match!" << endl;
}
}
Bizarrely, the above code seems to work accurately for elements in indexes 1 to vector.size()-2 (remember that indexes in vectors for c++ begin and zero). But index 0 or vector.size()-1 - i.e. the first and last elements of each vector - always yields a "Not a match!", no matter what the sentence. Everything in between is accurately compared, but those two positions aren't.
This is a very strange bug. Maybe my error lies in creating the second vector? This is the code I used:
int t = sentence.size() - 1;
for (int i = 0; i < sentence.size(); i++) {
reverseString[i] = sentence[t];
t--;
}
Am I inadvertently mutating something I shouldn't be for the first and last elements, in a way I can't quite see? Is my logic flawed? Please let me know what you think :)
EDIT: I am posting a Minimal, Complete, and Verifiable Example of my code below:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string input;
cout << "Please input a sentence - no preceding or trailing spaces."
" It will be analyzed accordingly: ";
getline(cin, input);
string secondString = "";
secondString[0] = input[0];
int i = 0;
for (i = 0; i <= input.length(); i++) {
// the below strips a string of punctuation if there is any,
// as these characters would mess up the comparison.
if (input[i] == ',' || input[i] == ';' || input[i] == ':' ||
input[i] == '.' || input[i] == '?' || input[i] == '!') {
} else {
secondString = secondString + input[i];
}
}
// now stuff the individual words in the string into a vector
vector<string> sentence;
// now we are going to stuff each word into a vector
string word;
stringstream ss(secondString);
while (getline(ss, word, ' ')) {
sentence.push_back(word);
}
// now for Task 1 - we will create a second vector that is reversed.
// Then compare both vectors - if identical, note it.
vector<string> reverseString;
reverseString = sentence;
int t = sentence.size() - 1;
for (int i = 0; i < sentence.size(); i++) {
reverseString[i] = sentence[t];
t--;
}
for (int i = 0; i < sentence.size(); i++) {
cout << "The index is " << i
<< " and the original string at this location is " << sentence[i]
<< " and the reverse string is " << reverseString[i] << endl;
if (sentence[i] == reverseString[i]) {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "A match!" << endl;
} else {
cout << reverseString[i] << "---" << sentence[i] << endl;
cout << "Not a match!" << endl;
}
}
return 0;
}
You have undefined behaviour because of the comparison in this line:
for (i = 0; i <= input.length(); i++)
Undefined behaviour happens as soon as the loop body tries to access input[i] while i is equal to input.length(). Make it:
for (i = 0; i < input.length(); i++)
It's just bad luck that the program didn't crash, or else you may have noticed the error earlier.
What happened to me when I tried it was that a superfluous space character was attached to secondString, which eventually caused the last element in sentence to have an extra space at the end, so the first and last words could never be equal.
Also note that the sentence-comparison code itself is too complicated, because you can achieve your goal in a much simpler manner with std::equal, std::vector's reverse iterator obtained by the rbegin() member function, and splitting the range in half, like in this example:
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
bool compare(std::vector<std::string> const& sentence)
{
// returns true if the range from the first to the middle element
// is equal to the range from the last to the middle element
return std::equal(
sentence.begin(),
sentence.begin() + sentence.size() / 2,
sentence.rbegin()
);
}
int main()
{
std::vector<std::string> const sentence1 = { "I", "am", "that", "am", "I" };
std::vector<std::string> const sentence2 = { "am", "that", "am", "I" };
std::vector<std::string> const sentence3 = { };
std::vector<std::string> const sentence4 = { "I", "am", "that", "that", "am", "I" };
std::vector<std::string> const sentence5 = { "I" };
std::cout << compare(sentence1) << "\n"; // true
std::cout << compare(sentence2) << "\n"; // false
std::cout << compare(sentence3) << "\n"; // true
std::cout << compare(sentence4) << "\n"; // true
std::cout << compare(sentence5) << "\n"; // true
}
This solution takes only one std::vector and does not perform more comparisons than necessary; when the middle element of a sentence is reached, the result is already known.
In contrast, your original code needlessly iterates the entire sentence:
for (int i = 0; i < sentence.size(); i++) {
For one thing, secondString[0] = input[0];is invalid when secondString
is empty. Likewise for (i = 0; i <= input.length(); should stop before
reaching input.length(). – Bo Persson 12 mins ago
Bo Persson's comment fixes your problem.