This is my line of code.
Can I replace this with much more graceful syntax?
if ( colDiffuseCompare == colDiffuseReplace && colAmbientCompare == colAmbientReplace && colEmissionCompare == colEmissionReplace && colSpecularCompare == colSpecularReplace)
{
return true;
}
else
{
return false;
}
You don't need the if() for such case:
return colDiffuseCompare == colDiffuseReplace &&
colAmbientCompare == colAmbientReplace &&
colEmissionCompare == colEmissionReplace &&
colSpecularCompare == colSpecularReplace;
There's no way to avoid combining the single conditions though.
Related
I want to iterate char by char in a vector of strings. In my code I created a nested loop to iterate over the string, but somehow I get an out of range vector.
void splitVowFromCons(std::vector<std::string>& userData, std::vector<std::string>& allCons, std::vector<std::string>& allVows){
for ( int q = 0; q < userData.size(); q++){
std::string userDataCheck = userData.at(q);
for ( int r = 0; r < userDataCheck.size(); r++){
if ((userDataCheck.at(r) == 'a') || (userDataCheck.at(r) == 'A') || (userDataCheck.at(r) == 'e') || (userDataCheck.at(r) == 'E') || (userDataCheck.at(r) == 'i') || (userDataCheck.at(r) == 'I') || (userDataCheck.at(r) == 'o') || (userDataCheck.at(r) == 'O') || (userDataCheck.at(r) == 'u') || (userDataCheck.at(r) == 'U')){
allVows.push_back(userData.at(r));
}
else if ((userDataCheck.at(r) >= 'A' && userDataCheck.at(r) <= 'Z') || (userDataCheck.at(r) >= 'a' && userDataCheck.at(r) <= 'z')){
allCons.push_back(userData.at(r));
}
else {
continue;;
}
}
}
}
The error here is in these lines:
allVows.push_back(userData.at(r));
allCons.push_back(userData.at(r));
the r variable is your index into the current string, but here you're using it to index into the vector, which looks like a typo to me. You can make this less error prone using range-for loops:
for (const std::string& str : userData) {
for (char c : str) {
if (c == 'a' || c == 'A' || ...) {
allVows.push_back(c);
}
else if (...) {
....
}
}
}
which I hope you'll agree also has the benefit of being more readable due to less noise. You can further simplify your checks with a few standard library functions:
for (const std::string& str : userData) {
for (char c : str) {
if (!std::isalpha(c)) continue; // skip non-alphabetical
char cap = std::toupper(c); // capitalise the char
if (cap == 'A' || cap == 'E' || cap == 'I' || cap == 'O' || cap == 'U') {
allVows.push_back(c);
}
else {
allCons.push_back(c);
}
}
}
Since this question is about debugging actually, I think it is a nice illustration of how the usage of std::algorithms of C++ can decrease the effort needed to see what is wrong with a non working code.
Here is how it can be restructured:
bool isVowel(char letter)
{
return letter == 'A' || letter == 'a' ||
letter == 'E' || letter == 'e'||
letter == 'O' || letter == 'o'||
letter == 'Y' || letter == 'y'||
letter == 'U' || letter == 'u';
}
bool isConsonant(char letter)
{
return std::isalpha(letter) && !isVowel(letter);
}
void categorizeLetters(const std::vector<std::string> &words, std::vector<char> &vowels, std::vector<char> &consonants)
{
for( const std::string &word : words){
std::copy_if(word.begin(), word.end(), std::back_inserter(vowels), isVowel);
std::copy_if(word.begin(), word.end(), std::back_inserter(consonants), isConsonant);
}
}
With a solution like this, you avoid the error-prone access-with-index that lead to your problem. Also, code is readable and comprehensive
I am new to programming and I need to search any string to see if it includes only the letters a,b,c,d,e or f. The minute the program finds a letter that is not one of those the program should return false. Here is my function
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true;
}
else {
return false;
}
index++;
}
}
Thank you very much for nay help! :)
The moment the return statement is encountered, the function is exited. This means that the moment any of the characters 'a', 'b', 'c', 'd', 'e', 'f' is encountered while iterating, due to the return statement the function will be exited immediately.
You can use std::string::find_first_not_of as shown below:
std::string input = "somearbitrarystring";
std::string validChars = "abcdef";
std::size_t found = input.find_first_not_of(validChars);
if(found != std::string::npos)
std::cout << "Found nonfavorite character " <<input[found]<<" at position "<<found<< std::endl;
else
{
std::cout<<"Only favorite characters found"<<std::endl;
}
If you unroll the loop by hand, you will spot the problem immediately:
if ((word[0] == 'a') || (word[0] == 'b') || (word[0] == 'c')||
(word[0] == 'd')|| (word[0] == 'e')|| (word[0] == 'f')) {
return true;
}
else {
return false;
}
if ((word[1] == 'a') || (word[1] == 'b') || (word[1] == 'c')||
(word[1] == 'd')|| (word[1] == 'e')|| (word[1] == 'f')) {
return true;
}
else {
return false;
}
//...
That is, the return value depends only on the first element.
"The minute the program finds a letter that is not one of those the program should return false" means
if ((word[0] != 'a') || (word[0] != 'b') || (word[0] != 'c')||
(word[0] != 'd')|| (word[0] != 'e')|| (word[0] != 'f')) {
return false;
}
if ((word[1] != 'a') || (word[1] != 'b') || (word[1] != 'c')||
(word[1] != 'd')|| (word[1] != 'e')|| (word[1] != 'f')) {
return false;
}
// ...
// After checking all the characters, you know what all them were in
// your desired set, so you can return unconditionally.
return true;
or, with a loop:
while (index < length) {
if ((word[index] != 'a') || (word[index] != 'b') || (word[index] != 'c')||
(word[index] != 'd')|| (word[index] != 'e')|| (word[index] != 'f')) {
return false;
}
index++;
}
return true;
bool is_favorite(string word){
return ( word.find_first_not_of( "abcdef" ) == std::string::npos );
}
It returns true if, and only if, there are only the characters 'a' through 'f' in the string. Any other character ends the search immediately.
And if you exchange string word with const string & word, your function will not have to create a copy of each word you pass to it, but work on a read-only reference to it, improving efficiency.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (word[index] > 'f' || word[index] < 'a')
return false;
index++;
}
return true;
}
The return true is logically in the wrong place in your code.
Your version returns true as soon as it finds one letter that is a through f. It's premature to conclude that the whole string is valid at that point, because there may yet be an invalid character later in the string.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
return true; // This is premature.
}
else {
return false;
}
index++;
}
}
Minimal change that illustrates where the return true should be: after the loop. The return true is reached only if and only if we did not detect any invalid characters in the loop.
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if ((word[index] == 'a') || (word[index] == 'b') || (word[index] == 'c')||
(word[index] == 'd')|| (word[index] == 'e')|| (word[index] == 'f')) {
// Do nothing here
}
else {
return false;
}
index++;
}
return true;
}
Obviously now that the affirmative block of the if is empty, you could refactor a little and only check for the negative condition. The logic of it should read closely to the way you described the problem in words:
"The minute the program finds a letter that is not one of those the program should return false."
bool is_favorite(string word){
int length = word.length(); // "word" is the string.
int index = 0;
while (index < length) {
if (!is_letter_a_through_f((word[index])
return false;
index++;
}
return true;
}
I replaced your large logical check against many characters with a function in the above code to make it more readable. I trust you do that without difficulty. My own preference is to keep statements short so that they are readable, and so that when you read the code, you can hold in your short-term memory the logic of what you are saying about control flow without being overloaded by the mechanics of your letter comparison.
https://leetcode.com/problems/regular-expression-matching
I was doing this practice problem (cpp) and while faster solutions are in the comments, I would like to understand why my code isn't working. This fails with s = "mississippi" and p = "mis*is*p*.". Tracing through the code, I figured it would correctly remove the first two letters, then when seeing the s* it would go through the s in the string (two of them), then remove the i in both, remove all the s (again 2) then remove all the p's (which is none, because it's compared against the i in the first string, so it should not modify that string). Finally, the '.' would match with the first p and remove both. So the final string should be "pi" and return false when the length is compared to zero.
class Solution {
public:
bool isMatch(string s, string p) {
while (s.length() > 0){
if (p.length() == 0){
return false;
}else if (p.length() == 1){
return p.compare(s) == 0 || p.at(0) == '.';
}else{
if (p.at(1) == '*'){
char c = p.at(0);
p = p.substr(2);
if (c == '.'){
return true;
}
int spot = 0;
while(spot < s.length() && s.at(spot) == c){
spot++;
}
if (spot != 0){
s = s.substr(spot);
}
}else{
if (s.at(0) != p.at(0) && p.at(0) != '.'){
return false;
}
s = s.substr(1);
p = p.substr(1);
}
}
}
return s.length() == 0;
}
};
Your logic is faulty here
return p.compare(s) == 0 || p.at(0) == '.';
That should be
return p.compare(s) == 0 || (s.length() == 1 && p.at(0) == '.');
That took me five minutes to find, two minutes looking at the code without seeing the problem, and then three minutes using a debugger to track down the logic error. You really should learn to use a debugger, much more efficient than asking on SO.
Some tips here.
Why does the compiler issue the warning: Expression results unused in the last else statement of this code?
PowerballLottery::WinningPossibility PowerballLottery::checkTicket(PowerballTicket ticket)
{
int count = 0;
if (ticket.getBall1() == getball1() || ticket.getBall1() == getball2() || ticket.getBall1() == getball3() || ticket.getBall1() == getball4() || ticket.getBall1() == getball5())
count++;
if (ticket.getBall2() == getball1() || ticket.getBall2() == getball2() || ticket.getBall2() == getball3() || ticket.getBall2() == getball4() || ticket.getBall2() == getball5())
count++;
if (ticket.getBall3() == getball1() || ticket.getBall3() == getball2() || ticket.getBall3() == getball3() || ticket.getBall3() == getball4() || ticket.getBall3() == getball5())
count++;
if (ticket.getBall4() == getball1() || ticket.getBall4() == getball2() || ticket.getBall4() == getball3() || ticket.getBall4() == getball4() || ticket.getBall4() == getball5())
count++;
if (ticket.getBall5() == getball1() || ticket.getBall5() == getball2() || ticket.getBall5() == getball3() || ticket.getBall5() == getball4() || ticket.getBall5() == getball5())
count++;
bool match = false;
if (ticket.getPowerball() == getpowerball())
match = true;
if ((count == 0) && (match == false))
return PowerballLottery::WinningPossibility::NOTWINNING;
else if ((count == 0) && (match == true))
return PowerballLottery::WinningPossibility::POWERBALL;
else if ((count == 1) && (match == true))
return PowerballLottery::WinningPossibility::ONEPLUSPOWERBALL;
else if ((count == 2) && (match == true))
return PowerballLottery::WinningPossibility::TWOPLUSPOWERBALL;
else if ((count == 3) && (match == false))
return PowerballLottery::WinningPossibility::THREE;
else if ((count == 3) && (match == true))
return PowerballLottery::WinningPossibility::THREEPLUSPOWERBALL;
else if ((count == 4) && (match == false))
return PowerballLottery::WinningPossibility::FOUR;
else if ((count == 4) && (match == true))
return PowerballLottery::WinningPossibility::FOURPLUSPOWERBALL;
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else ((count == 5) && (match == true));
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
}
Effectively, the code is
if ((count == 0) && (match == false))
....
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else
((count == 5) && (match == true)); //<- Expression results unused
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
As said from #AlexD's answer this is primarily a problem with how you had formatted the code, and that warning appears because
else ((count == 5) && (match == true));
that statement actually isn't used to do any computation stored in a result, or making a branch decision based on it.
The
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
statement is executed regardless anyways.
Reminds a bit about the famous apple OpenSSL goto fail; bug:
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; /* MISTAKE! THIS LINE SHOULD NOT BE HERE */
Others have already pointed out the problem the compiler was warning you about.
Now let's consider the problem it didn't warn you about: your code is much more complex than there's any good reason for it to be.
In essence, the users picks and the balls chosen in the lottery (other than the power-ball) form sets. What we care about is the size of the intersection of those two sets. The C++ standard library gives us tools to make that task a lot simpler (and it looks to me like the way you've designed your PowerBallTicket class is doing more to hinder than help too):
std::set<int> lottery {
getball1(),
getball2(),
getball3(),
getball4(),
getball5()
};
std::set<int> tick {
ticket.getball1(),
ticket.getball2(),
ticket.getball3(),
ticket.getball4(),
ticket.getball5()
};
std::vector<int> matches;
std::set_intersection(lottery.begin(), lottery.end(),
tick.begin(), tick.end(),
std::back_inserter(matches));
That gives us the matches between the two. From there, we have the problem of converting the number of matches (plus whether the Powerball matched) to choose which enumeration value to return. One easy way to do that is to is an array:
WinningPossibility rets[][6] = {
{ NOTWINNING, ONE, TWO, THREE, FOUR, FIVE},
{ POWERBALL, ONEPLUS, TWOPLUS, THREEPLUS, FOURPLUS, FIVEPLUS }
};
With those in place, our return looks something like this:
return rets[ticket.getpowerball() == getpowerball()][matches.size()];
The code above points toward an improvement: instead of all those getballX() member functions, you should just store the data in a set to start with, and operate directly on those sets. In this case, it looks like you have quasi-classes, with "encapsulation" that's losing a great deal, and gaining little (probably nothing).
You can say else <statement> or else if (<expression>) <statement>; you have the expression without the if, which the compiler is doing its best with.
While reviewing code, I have come across a few if staments using ! followed by an != in the assessment e.g.
if (!(fs.ReadByte() != (byte)'D' ||
fs.ReadByte() != (byte)'I' ||
fs.ReadByte() != (byte)'C' ||
fs.ReadByte() != (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Is there any reason to use a double negative over assessing positive e.g.
if ((fs.ReadByte() == (byte)'D' ||
fs.ReadByte() == (byte)'I' ||
fs.ReadByte() == (byte)'C' ||
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Thanks
Those two are different. The first says "None of these are not equal", the second says "any of these are equal".
If you applied the ! operator across them, you'd have to change the || to an &&:
if ((fs.ReadByte() == (byte)'D' &&
fs.ReadByte() == (byte)'I' &&
fs.ReadByte() == (byte)'C' &&
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}