Evaluate expression in a string recursively - c++

Lets say we would like to evaluate expressions in a string. Expressions represented by (###) for simplicity in the example. We only count the hashtags in the example for simplicity. Expressions can be nested.
#include <iostream>
#include <string>
std::string expression{ "(###(##)#(###)##)" };
int countHash(std::string::iterator stringIterator, std::string::iterator stringEnd)
{
int result = 0;
while (stringIterator != stringEnd)
{
if (*stringIterator == '#')
{
result += 1;
}
else if (*stringIterator == '(')
{
result += countHash(++stringIterator, stringEnd);
}
else if (*stringIterator == ')')
{
return result += countHash(++stringIterator, stringEnd);
}
++stringIterator;
}
return result;
}
int main()
{
std::cout << countHash(expression.begin(), expression.end()) << std::endl;
return 0;
}
Output: 51
Expexted output: 11
So my problem is when I return from the recursive call the iterator is not updated. It is behind. The processing goes through parts of the string multiple times. How should I handle this?
My main goal by the way is to be able to evaluate expressions like this:
std::string expr = "(+1 (+22 3 25) 5 (+44 (*3 2)))";
EXPECT(106== evalExpression(expr.begin(), expr.end()));
Thanks.
EDIT:
I updated my question based on the suggestions in the comments.

#include <string>
#include <iostream>
std::string expression{ "#####-###-##" };
int countHash(std::string::iterator & stringIterator, std::string::iterator stringEnd)
{
int result = 0;
while (stringIterator != stringEnd)
{
switch (*stringIterator++)
{
case '#':
result += 1;
break;
case '-':
result += countHash(stringIterator, stringEnd);
break;
default:
// indicate error ?
break;
}
}
return result;
}
int main()
{
std::string::iterator b = expression.begin();
std::cout << countHash(b, expression.end()) << std::endl;
return 0;
}

OK so as I edited my original question, here is a solution for that:
#include <iostream>
#include <string>
std::string expression{ "(###((##)#)(#(#)#)#(#))" };
int countHash(std::string::iterator& stringIterator, std::string::iterator stringEnd)
{
int result = 0;
while (stringIterator != stringEnd)
{
if (*stringIterator == '#')
{
result += 1;
}
else if (*stringIterator == '(')
{
result += countHash(++stringIterator, stringEnd);
continue;
}
else if (*stringIterator == ')')
{
++stringIterator;
return result;
}
++stringIterator;
}
return result;
}
int countHash(std::string expression)
{
auto it = expression.begin();
return countHash(it, expression.end());
}
int main()
{
std::cout << countHash(expression) << std::endl;
return 0;
}
Output: 11
So one important thing was that you need to pass the string by reference to avoid processing the same segments of the string multiple times after you return from your recursive calls.
What I also had difficulty with is that you need to do a continue after the recursive call in my while loop. This is because you don't want to increment stringIterator after your return from the recursive call.
You could also do this with the post increment operator and with a switch-case as #bruno did it in his answer. That was the insight for me. If you are not only checking for characters switch-case is not possible though. You could use a do-while loop but I don't like that.
On more important thing was that you need to increment your iterator before returning from the ) branch. That is because that's the end of an expression and if it was a recursive call you want to go on with the expression on the caller side.
One other problem was that you cant pass expression.begin() if your function takes a reference to iterator.
For the
std::string expr = "(+1 (+22 3 25) 5 (+44 (*3 2)))";
expression my solution is available at https://github.com/bencemeszaroshu/expeval/blob/master/expeval/expeval.cpp. I don't like it as it is now but I will try to improve it later. (Happy to hear suggestions.) It is working however. Thanks everyone for your help, I'm marking #bruno answer as accepted because it helped me the most.

Related

Returning the complete value in recursions

I've written a C++ code to convert a base 10 number into base two, but don't want the function to print it, but to return the value since I'll later need to use it in another function. The problem with returning is that the first time it returns it'll break out of the function, so it won't finish the process of converting and instead of returning '101' for '5', it will simply return '1' and that's it. Any ideas to fix this? I appreciate in advance.
Here's also my code:
int two;
int base(int a)
{
if(a==1)
{
two=a%2;
}
else
{
base(a/2);
two=a%2;
}
return two;
}
Note: Of course the code works pretty well if I change the return type into void and simply print the value. But I want to RETURN the value.
Implementation of summing up (in fact it can be implemented iteratively but it seems you need to apply recursion so I provided recursive solution):
int baseHelper(int a, int factor)
{
int returnedValue = 0;
if(a==0 || a==1)
returnedValue = factor * a;
else
{
int addend = factor * (a%2);
returnedValue = addend + baseHelper(a/2, factor*10);
}
return returnedValue;
}
int base(int a)
{
return baseHelper(a, 1);
}
int main()
{
for(int i=0; i<=256; i++)
cout << "i=" << i << " " << base(i) << endl;
return 0;
}
If you want to use recursion, you can return std::string like this:
std::string base(int a)
{
if (a == 0)
return "0";
else if (a == 1)
return "1";
else
return base(a / 2) + ((a % 2) ? "1" : "0");
}
Using std::to_chars or std::from_chars from <charconv> is also an alternative.

Iterating over list of structs

I'm creating a list of structs:
struct task{
int task_id;
bool is_done;
char* buffer;
int length;
} task;
list<task> taskList;
And trying to iterate over the tasks in order to check the is_done status:
for (std::list<task>::const_iterator iterator = taskList.begin(), end = taskList.end(); iterator != end; ++iterator) {
if(iterator->is_done) {
return 1;
} else {
return 2;
}
}
Where am I wrong?
I get: Missing template argument before '->' token
The iterator's operator-> does the dereferencing already. So instead of
if(*iterator->is_done==true)
you need
if(iterator->is_done==true)
is equivalent to
if((*iterator).is_done==true)
which as a sidenote is equivalent to the easier to read
if((*iterator).is_done)
or
if(iterator->is_done)
. Even better, you could also use std::any_of:
#include <algorithm>
....
if (any_of(begin(taskList), end(taskList),
[](task const &t) { return t.is_done; }))
{
return 1;
} else {
return 2;
}
Informal note: There is no need to qualify any_of, begin and end with std::, because taskList is of type std::list<?>, and the C++-compiler will look up those functions in the std-namespace for you already.
Like this
if (iterator->is_done==true){
no need for * and ->.
And not the question you asked but
if (iterator->is_done==true) {
is exactly the same as the easier to understand
if (iterator->is_done) {
Don't compare booleans to true and false, they already are true and false.
Use std::find_if instead:
#include <algorithm>
...
bool isDone(const task &task)
{
return task.is_done;
}
...
return std::find_if(taskList.begin(), taskList.end(), isDone) == taskList.end() ? 2 : 1;
Try this. Note change to task struct and referencing iterator. (I changed name of iterator - to be more concise - but not actually required). I just think looks less confusing.
#include <list>
using namespace std;
struct task{
int task_id;
bool is_done;
char* buffer;
int length;
};
int main() {
std::list<task> taskList;
task task1;
task1.buffer = "qwerty";
task1.is_done = true;
task1.length = 6;
task1.task_id = 1;
taskList.push_back(task1);
for (std::list<task>::const_iterator it = taskList.begin(), end = taskList.end();
it != end; ++it) {
if((*it).is_done==true)
return 1;
else
return 2;
}
return 0;
}

Changing while loop to accommodate two situations

Suppose I have a while loop that depends on two separate inputs. In situation one, the while loop will take the value 1, and in situation two, it should take !cin.eof(). Is there a way I can do this efficiently? To be more concise:
string hello;
cin >> hello;
if(hello == "one")
{
//make the while loop depend on value 1
}
else if(hello == "two")
{
//make the while loop depend on value !cin.eof()
}
while(/*depends on above conditional*/)
{}
I don't want to do something like:
if(hello == "one)
{
while(1){}
}
else if(hello == "two")
{
while(!cin.eof){}
}
because the while loop essentially does the same thing in each situation.
For readability and in the interest of cohesion, I think you should move the contents of your loop into a separate function:
void DoSomething() { /* ... */ }
// ...
if(hello == "one)
{
while(1){ DoSomething(); }
}
else if(hello == "two")
{
while(!cin.eof){ DoSomething(); }
}
It's easier to see that the different while loops are doing the same thing but their conditions are different.
I believe you're looking for something like this:
while((hello == "one") || (hello == "two" && !cin.eof)) {
}
This code will do what you want, because it checks 'is the variable "one"? If so, keep executing. If it's not, it'll check: Is the variable "two"? If so, it'll check for cin.eof.
If it's neither, the loop won't execute. (the && 1 in the first condition was omitted, because it's always 'true', equalling and infinite loop)
Edit:
To simplify things, you may want to consider this code (as suggested in the comments):
bool HelloIsOne = (strcmp(hello, "one") == 0);
bool HelloIsTwo = (strcmp(hello, "two") == 0);
while(HelloIsOne || HelloIsTwo && !cin.eof) {
}
The brackets, which I placed in the previous example are actually unnecessary, because && binds stronger than ||, but they help the general clarity of the code.
Simply use or (||) as a condition in the while loop. Set the first condition if(hello == "one"). Now you have a while loop that will loop if one of the conditions is true.
bool value = hello == "one";
while (value || !cin.eof) {}
If you're using C++11:
#include <functional>
auto check = (hello == "one") ? []() bool -> { return 1; } :
[]() bool -> { return !cin.eof(); };
while(check) {
};
How about this:
switch(hello)
{
case 'one':
{
for(; 1; );
{
// your loop here
}
break;
}
case 'two':
{
for(;!cin.eof; )
{
// your other loop here
}
break;
}
default:
{
cout << " shouldnt get here unless bad user input" << endl;
break;
}
}
You can do something like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string hello;
cin >> hello;
while(hello=="one"?1:(!cin.eof()))
{
//do stuff
}
return 0;
}
It checks if the string hello is "one" and if it's true, the condition of the while is 1, else it is !cin.eof() as you wanted.

Using a function call in a case statement label

Can you have a function call as a case statement label. For instance:
char x
switch(x)
{
case isCapital():
capitalcount++;
break;
case isVowel():
vowelcount++;
break;
.
.
.
.
.
}
Is this permitted within C++?
The value in a case label needs to be a constant expression. That is, the answer to your immediate question is: yes, you can call certain functions in a case label. However, not the ones you tried to call. You can have multiple labels refer to one group of statements, though:
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
do_vowels();
break;
I know this doesn't answer your question per se, but you might try coding it like this....
capitalcount += isCapital(x);
vowelcount += isVowel(x);
The boolean return type of the isXXX() functions would get promoted to an int and added to the counts as either 0 (false) or 1 (true).
First of all: in your desired code isCapital and isVowel should be not functions (and not a function call, definitely), but functors -- because to check a value they have to receive it via parameters...
anyway your code is not possible in C++... but can be simulated with a sequence of pairs of functions: predicate + effect. Predicate have to take some parameter and respond with a boolean. Effect will do smth if predicate is true. To simulate break and fallback to next case (i.e. when no break in a case) effect function also have to return a boolean.
Sample code may look like this:
#include <cctype>
#include <functional>
#include <iostream>
#include <vector>
int main(int argc, char* argv[])
{
typedef std::vector<
std::pair<
std::function<bool(char)> // predicate
, std::function<bool()> // effect: return true if `break' required
>
> case_seq_t;
unsigned digits = 0;
unsigned upper = 0;
unsigned lower = 0;
unsigned total = 0;
unsigned other = 0;
case_seq_t switch_seq = {
{
// predicate lambda can be replaced by std::bind
// in this simple case... but need to change param type.
// std::bind(&std::isdigit, std::placeholders::_1)
[](char c) { return std::isdigit(c); }
, [&]() { digits++; return true; }
}
, {
[](char c) { return std::islower(c); }
, [&]() { lower++; return true; }
}
, {
[](char c) { return std::isupper(c); }
, [&]() { upper++; return true; }
}
// `default` case
, {
[](char c) { return true; }
, [&]() { other++; return true; }
}
};
for (int i = 1; i < argc; i++)
for (int pos = 0; argv[i][pos]; pos++)
for (const auto& p : switch_seq)
if (p.first(argv[i][pos]))
if (p.second())
break;
std::cout << "digits=" << digits << std::endl;
std::cout << "upper=" << upper << std::endl;
std::cout << "lower=" << lower << std::endl;
std::cout << "other=" << other << std::endl;
return 0;
}
Not so simple as switch but (IMHO) obvious enough... and maybe, in some real cases, have better flexibility (and probably maintainability) :)

Learning recursion: How can I locate a substring index within a string without using find?

I have a recursive function to find the starting index of a substring within a string. I am learning to use recursion, so the find function is not allowed. I believe I have met most of the conditions. This function is supposed to find the correct index in the string. If it is blank it returns -1.
Here is the real problem. If I enter a string "nothing" and search for "jax" it doesn't return -1. I don't understand why. Any help please? Here is the code:
The user would enter string s and t passed into below:
int index_of(string s, string t)
{
int start = 0;
int len2 = t.length();
int index = 0;
if (s == "")
{
return -1;
}
else if (s.substr(1).length() <= t.length())
{
return -1;
}
else if ( s.substr(start, len2) == t)
{
return index;
}
else
{
index ++;
return index + index_of(s.substr(1), t);
}
return -1;
}
There are several problems -- some minor ones, and some quite important ones.
You have two variables, start and index, to indicate "the current position", but one would be enough.
index can only be 0 or 1. Therefore, the way it is currently written, you could easily get rid of index and start altogether.
Important: When, during the final recursion, the end of the string is reached, you return -1 to the previous recursive call. Then, because of the way the recursive calls are done, you add 1 and return that to the previous call, and so forth. The value finally returned is the -1 plus the length of the string. That is why you get strange results.
This comparison
if (s.substr(1).length() <= t.length())
does not make much sense.
Taking all of this into account, here is an improved version:
#include <iostream>
#include <string>
int index_of(
const std::string &s,
const std::string &t,
const size_t index)
{
int len2 = t.length();
if ((s.length() - index) < t.length())
return -1;
else if (s.substr(index,len2) == t)
return index;
else
return index_of(s,t,index + 1);
return -1;
}
/** Overloading, so you can call index_of with just
two arguments */
int index_of(const std::string &s, const std::string &t)
{
return index_of(s,t,0);
}
/** Some test cases. */
int main()
{
std::cout << index_of("hello","ello") << std::endl;
std::cout << index_of("nothing","jax") << std::endl;
std::cout << index_of("hello","llo") << std::endl;
std::cout << index_of("hello","lo") << std::endl;
std::cout << index_of("hello","o") << std::endl;
std::cout << index_of("hello","hel") << std::endl;
}
The best way to learn how to debug problems like this is to work them out on paper. Your example is small enough that it shouldn't take too long. It's pretty clear that you're going to fall into your else case in the first few steps because the strings don't match. So we have:
index_of("nothing", "jax"):
index++; // index is now 1
return 1 + index_of("othing", "jax");
index_of("othing", "jax"):
index++; // index is now 1
return 1 + index_of("thing", "jax");
etc.
Does that help?