Counting vowels c++ - c++

While user inputs 10 alphabets, program should tell how many of them are vowels. I have written this code:
while (count<10)
{
cin >> n;
count++;
if (n == 'A' || n == 'a' && n == 'E' || n == 'e' && n == 'I' || n == 'i' && n == 'O' || n == 'o' && n == 'U' || n == 'u')
{
total++;
}
}
cout << total << endl;
This generates output of 0 even if there are vowels entered by user. something wrong?

Let's start by cutting down the condition down a bit, to only look at a and e
if (n == 'A' || n == 'a' && n == 'E' || n == 'e')
and then only considering the lowercase letters for simplicity (but retains the problem)
if (n == 'a' && n == 'e')
if you read this out loud it says "if n is 'a' AND n is 'e'". The "AND" (from the && operator) means that both conditions must be true. You've created an impossible condition here, if n is 'a', then it is not 'e', so you get if (true && false) - which is false. If n is 'e', then it is not 'a', so you get if (false && true).
Simply replace all of your && (and) operators with || (or) operators to have the condition be true if at least one of your equality comparisons is true.
if (n == 'A' || n == 'a' || n == 'E' || n == 'e'
|| n == 'I' || n == 'i' || n == 'O' || n == 'o'
|| n == 'U' || n == 'u')
There are some ways to simplify the condition.
One is to add a #include <cctype> and use std::tolower to convert n to lowercase, then you only need to compare against lowercase characters.
n = std::tolower(n);
if (n == 'a' || n == 'e' || n == 'i' || n == 'o' || n == 'u')
Another, less repetitive approach is to create a std::string with all the vowels in it, and then see if it contains n, #include <string> up top.
std::string vowels = "aeiouAEIOU";
while (/*...*/) {
// ...
if (vowels.find(n) != std::string::npos) {
++total;
}
}
As n314159 pointed out, if you are using C++17 or later, you can use a std::string_view instead, which is cheaper. #include <string_view>
static constexpr std::string_view vowels = "aeiouAEIOU";
while (/*...*/) {
// ...
if (vowels.find(n) != std::string_view::npos) {
++total;
}
}

I recommend using a switch statement with fall-through, which is more readable but also potentially more efficient (may be implemented with jump table).
int count = 10;
while (count--) {
switch(std::tolower(n)) {
case 'a': case 'e':
case 'i': case 'o':
case 'u': total ++; break;
default:;
}
}

Related

Why is iteration through a char vector is faster than the iteration through a string in C++

I am practicing a coding challenge where I have to reverse the vowels in a string.
My first approach failed because of exeeding Time limit. Here is my first approach using string iteration to reverse the vowels in a string.
string reverseVowels(string s) {
string str = "";
//storing the vowels from the string into another string
for (auto x : s)
if (x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u' || x == 'A' || x == 'E' || x == 'I' || x == 'O' || x == 'U')
str = str + x;
//swapping the vowels
int count = 0;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u' || s[i] == 'A' || s[i] == 'E' || s[i] == 'I' || s[i] == 'O' || s[i] == 'U')
{
s[i] = str[count];
count++;
}
}
return s;
}
My second approach using the char vector iteration had passed all the tests. Here is my second approach
class Solution {
public:
string reverseVowels(string s) {
vector<char> v;
//storing the vowels from the string into vector
for (auto x : s)
if (x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u' || x == 'A' || x == 'E' || x == 'I' || x == 'O' || x == 'U')
v.push_back(x);
//swapping the vowels
int count = 0;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u' || s[i] == 'A' || s[i] == 'E' || s[i] == 'I' || s[i] == 'O' || s[i] == 'U')
{
s[i] = v[count];
count++;
}
}
return s;
}
};
Could you explain why my first method failed the tests but second method passed the tests
Replace str = str + x; with str.push_back(x); or str += x;, and you'll likely see the same performance as with vector.
str = str + x; makes a copy of str, appends the character to that copy, then makes another copy when assigning back to str. As a result, your algorithm is quadratic, for no good reason.
It's because you're doing str = str + x, that creates an unnecessary copy of str, but std::vector::push_back or std::string::push_back appends a character to the vector or string, which is much faster than creating a copy of str.
str = str + x
this creates an additional copy of str while copying.
std::vector::push_back
this straight appends to the vector string

How can I switch what points on an array equal in c++?

These change the array that I print to the screen. direc is an input before this. However, when array[1][2] == '#', it still moves '#' to array[1][0].
if (array[1][1] == '#' && direc == 'A' || direc == 'a' ) {
array[1][1] = '_';
array[1][0] = '#';
}
else {
if (array[1][1] == '#' && direc == 'D' || direc == 'd' ) {
array[1][1] = '_';
array[1][2] = '#';
}
else {
if (array[1][2] == '#' && direc == 'A' || direc == 'a' ) {
array[1][1] = '#';
array[1][2] = '_';
}
}
}
You can either add parentheses, as already noted in the comments, like this
if (array[1][1] == '#' && (direc == 'A' || direc == 'a' )) {
Alternatively you could use std::tolower in which case you no longer nee
if (array[1][1] == '#' && std::tolower(direc) == 'a') {
You could still add extra parentheses if you are not comfortable that operator && is lower precedence than operator ==
(the full table of operator precedences can be seen here)

how do you change arrays?

help! im trying to replace 'a' and 'e' with ' ' in my array but it keeps replacing all of the array instead.
for(int x = 0; x < array_length); x++)
{
if(city_name[x] == 'a' || 'e')
city_name[x] = " ";
}
if(city_name[x] == 'a' || 'e')
should be
if(city_name[x] == 'a' || city_name[x] == 'e')
Your code is equivalent to
if( ( city_name[x] == 'a' ) || 'e')
which does city_name[x] == 'a' and then checks the result of that statement || 'e'
First of all the loop is wrong. it contains a typo
for(int x = 0; x < array_length); x++)
^^^
Remove the redundant parenthesis.
Also this condition
city_name[x] == 'a' || 'e'
is always equal to true because it is equivalent to
( city_name[x] == 'a' ) || 'e'
And instead of string literal " " you have to use character literal ' '
The correct loop can look like
for ( int i = 0; i < array_length; i++ )
{
if ( city_name[i] == 'a' || city_name[i] == 'e' ) city_name[i] = ' ';
}
Take into account that there is standard algorithm std::replace_if declared in header <algorithm> that can be used instead of the loop. For example
std::replace_if( city_name, city_name + array_length,
[]( char c ) { return c == 'a' || c == 'e'; },
' ' );

Program to count evens odds vowels and consonants in a string

Hello i don't know how to fix my program to find how many evens, odds, vowels and consonants are in my string.
The program compiles and runs but i never get any vowels or consonants and everything else is added in either evens or odds (even characters).
Edit 1: By evens and odds i mean like if the user types in the string John123 i want to find how many characters are vowels in this case 1 the 'o' how many are consonants in this case 3 the 'J', 'h', 'n' how many are evens in this case 1 the '2' and how many are odds in this case 2 the '1' and the '3'.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string s1;
int evens = 0; //
int odds = 0; //
int vowels = 0; //
int consonants = 0; //
cout << "Please type in Something: ";
getline(cin, s1);
cout << "You typed: " << s1 << endl;
for(int i = 0; i < s1.size(); ++i)
{
if((s1[i] % 2) == 0 )
{
++evens;
}
else if((s1[i] % 2 ) != 0) // What would an algorithm (formula) be to find when a number is odd without the not-equals != ?
{
++odds;
}
else if(s1[i] == 'A' || 'a' || 'E' || 'e' || 'O' || 'o' || 'I' || 'i' || 'U' || 'u')
{
++vowels;
}
else if(s1[i] == 'Q' || 'W' || 'R' || 'T' || 'Y' || 'P' || 'S' || 'D' || 'F' || 'G' || 'H' || 'J' || 'K' || 'L' || 'Z' || 'X' || 'C' || 'V' || 'B' || 'N' || 'M'||
'q' || 'w' || 'r' || 't' || 'y' || 'p' || 's' || 'd' || 'f' || 'g' || 'h' || 'j' || 'k' || 'l' || 'z' || 'x' || 'c' || 'v' || 'b' || 'n' || 'm')
// I specify every letter so that it dosn't pick whitespaces, symbols etc.
{
++consonants;
}
}
cout << "Evens in string are: " << evens << "\nOdds in string are: " << odds << "\nVowels in string are: " << vowels << "\nConsonants in string are: " << consonants;
return 0;
}
if((s1[i] % 2) == 0 )
This code is not correct. You are modulating the character, which isn't what you want. You want to first convert the character to an integer using atoi or something like that, I can't remember the function. (Just look up string to int c++). Then, once you've converted the character to an integer, then you can modulate it correctly.
Also, your || syntax is totally wrong, as Jongware mentioned. You need to have an == comparison for each character.
Should look like this (very long):
(s1[i] == 'A' || s1[i] == 'a' || s1[i] == 'E' || s1[i] == 'e' || s1[i] == 'O' || s1[i] == 'o' || s1[i] == 'I' || s1[i] == 'i' || s1[i] == 'U' || s1[i] == 'u')
You might want to store s1[i] in a char beforehand so it's more concise.
And you should place your character testing BEFORE the odd/even testing, so that you don't accidentally try and convert h or another non-numeric character to an integer.
A char is a number. For example, a is (on most computers) the ASCII code 97. So either your even test or your odd test will always match. You need to rearrange your if blocks.
Also, your character tests don't do what you intended. s1[i] == 'A' || 'a' tests as true whenever s1[i] is equal to 'A' or whenever 'a' as a number is not zero. But 97 is never zero, so that test will always result in true. You need code more like s1[i] == 'A' || s1[i] == 'a', testing the s1[i] value each time.
(One way to make things simpler: Once you know the character is not a vowel, you can test for an ASCII consonant with ((s1[i] >= 'a' && s1[i] <= 'z') || (s1[i] >= 'A' && s1[i] <= 'Z')).)
You have basically two problems:
Characters are interpreted as numbers, taking into account the character code. When you are checking whether the character is even or odd, you are checking its character code which will always be either event of odd, this is why your code will always enter into the first or second case. You must check whether your character is digit and if so, you must check whether it is even
Your OR is incorrect, see Ruby van Soelen's answer
Suggested, untested code:
for(int i = 0; i < s1.size(); ++i)
{
if (isdigit(s1[i])) {
if ((s1[i] == '0') || (s1[i] == '2') || (s1[i] == '4') || (s1[i] == '6') || (s1[i] == '8'))
{
++evens;
}
else // What would an algorithm (formula) be to find when a number is odd without the not-equals != ?
{
++odds;
}
}
else
{
if(s1[i]=='A' || s1[i]=='a' || s1[i]=='E' || s1[i]=='e' || s1[i]=='O' || s1[i]=='o' || s1[i]=='I' || s1[i]=='i' || s1[i]=='U' || s1[i]=='u')
{
++vowels;
}
else if(s1[i]=='B' || s1[i]=='b' || s1[i]=='C' || s1[i]=='c' || s1[i]=='D' || s1[i]=='d' || s1[i]=='F' || s1[i]=='f' || s1[i]=='G' || s1[i]=='g' || s1[i]=='H' || s1[i]=='h' || s1[i]=='J' || s1[i]=='j' || s1[i]=='K' || s1[i]=='k' || s1[i]=='L' || s1[i]=='l' || s1[i]=='M' || s1[i]=='m' || s1[i]=='N' || s1[i]=='n' || s1[i]=='P' || s1[i]=='p' || s1[i]=='Q' || s1[i]=='q' || s1[i]=='R' || s1[i]=='r' || s1[i]=='S' || s1[i]=='s' || s1[i]=='T' || s1[i]=='t' || s1[i]=='V' || s1[i]=='v' || s1[i]=='X' || s1[i]=='x' || s1[i]=='Y' || s1[i]=='y' || s1[i]=='Z' || s1[i]=='z')
// I specify every letter so that it dosn't pick whitespaces, symbols etc.
{
++consonants;
}
}
}
Your || syntax is making no sence, what you currently have is something like this
else if(s1[i] == 'A' || 'a' || 'E' || 'e' || 'O' || 'o' || 'I' || 'i' || 'U' || 'u')
while it should be like this:
else if(s1[i]=='A' || s1[i]=='a' || s1[i]=='E' || s1[i]=='e' || s1[i]=='O' || s1[i]=='o' || s1[i]=='I' || s1[i]=='i' || s1[i]=='U' || s1[i]=='u')
Expression in the else-if statement will be always equal to true
else if(s1[i] == 'A' || 'a' || 'E' || 'e' || 'O' || 'o' || 'I' || 'i' || 'U' || 'u')
becuase it is equivalent to
( s1[i] == 'A' ) || 'a' || 'B' /*...*/
where 'a' as it is not equal to zero evaluates to true.
So you have to write at least like
s1[i] == 'A' || s1[i] == 'a' || s1[i] == 'B' /*...*/
Also take into account that for example character 'B' though is not a digit but its code is even. So you will get a wrong result if will start checks from statement
if((s1[i] % 2) == 0 )
You should check at first whether the character is a digit. Also you could define an array of vowels and consonants and use standard function strchr that to check whether a character is a vowel or consonant.
For example
#include <iostream>
#include <string>
#include <cctype>
//...
const char *alpha_vowels = "AEIOU";
const char &alpha_consonants = "BCD...";
//...
if ( std::isdigit( s[i] ) )
{
s[i] % 2 == 0 ? ++evens : ++odds;
}
else if ( std::strchr( alpha_vowels, std::toupper( ( unsigned char )s[i] ) ) != nullptr )
{
++vowels;
}
else if ( std::strchr( alpha_consonants, std::toupper( ( unsigned char )s[i] ) ) != nullptr )
{
++consonants;
}
In addition to the other answers, here's a simpler way to accomplish the same thing.
std::set<char> vs{'a', 'o', 'u', 'e', 'i'};
for (auto&& c : s1) {
if (std::isdigit(c))
if ((c - '0') % 2 == 0) // Trick to convert numeric char -> int.
++evens;
else
++odds;
else if (std::isalpha(c))
if (vs.count(std::tolower(c)))
++vowels;
else
++consonants;
}

What is wrong with my logic?

if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
I am checking to see if the first indice is between 'A' and 'H' and the second indice is between 1 - 8.
so the argument would = 1 if the user entered { A, 1 }
-1 if the user entered { J, 1 }
And (&&) has higher precedence than or (||), so to express what you want you need:
if ((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
Otherwise what's happening is that it does the equivalent of this:
if (location[0] <= 'H' || (location[0] >= 'A' && location[1] <= 8) || location[1] >= 1)
Which is clearly not what you intended.
You can put as many expressions in the condition as you want, but you must remember the precedence rules; I suggest always using extra parentheses for clarity.
As Jeremiah has pointed out in the comments, the condition still wouldn't be doing what you wanted -- you are asking if something is in a given range by checking if it's either less than the upper bound or greater than the lower bound (this covers all input), when you intended to check whether the input was both larger than the lower bound and smaller than the upper:
if (location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
In this case, since the operators are all &&, no extra parentheses are needed, though you can add them for extra clarity.
You need &&s not ||s. For example: 'Z' >= 'A' || 'Z' <= 'H' is true.
if(location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
While not necessary in this case, you should group your logic together with parenthesis (and if they were ||s you would have to for it to work as expected):
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= 8 && location[1] >= 1))
Add parenthesis to group the conditions:
if( (location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If location[0] was equal to 'J' (definitely NOT between 'A' and 'H'), your if-clause would be TRUE because even though location[0] <= 'H' is FALSE, location[0] >= 'A' is TRUE and you are using || (OR). The problem is that you are using || (OR) instead of && (AND). You need to use all && (AND) in the if-clause.
&& has higher precedence than ||. So, you may want to write it as
if((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If you already tried this, please tell what error you got
Sorry guys, new here. I should have posted my entire method. Thank you for explaining the precedence of the operators, but my issue was that I was comparing a char with an int. All I needed to do was put ' ' around my numbers.
void GameBoard::enterShips()
{
char location[2];
int ships = 0;
int count = 1;
while( ships < NUM_SHIPS )
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location[0];
cin >> location[1];
cout << endl;
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= '8' && location[1] >= '1'))
{
location[0] = location[0] - 64;
location[1]--;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
else
{
cout << "Wrong coordinates entered. Try again." << endl << endl;
}
}
}
As you can see in this operator precedence table, && is #13. It's higher up than ||, which is #14.
Therefore:
if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
Is equivalent to:
if(location[0] <= 'H' || (location[0] >= 'A'
&& location[1] <= 8) || location[1] >= 1)
You want:
if((location[0] <= 'H' || location[0] >= 'A') &&
(location[1] <= 8 || location[1] >= 1))
Or even better:
if(((location[0] <= 'H') || (location[0] >= 'A')) &&
((location[1] <= 8) || (location[1] >= 1)))
I always put brackets around everything except when */ and +- are concerned. Even if you memorize the table, you shouldn't assume others do.
It helps code readability and helps prevent bugs... even compiler bugs! Triple bonus. :)
EDIT: Ah, you want ALL of them to be true. Just use all &&s, then! This works:
if(((location[0] <= 'H') && (location[0] >= 'A')) &&
((location[1] <= 8) && (location[1] >= 1)))