Keeping count in a recursive function? [Jython] - python

I'm trying to count the number of times the letter 'x' appears in a string using a recursive function. My function currently does this, however I wish to have only one parameter (the string). I am having difficulty creating a counter that is not overwritten when the function is iterated in the return line.
To illustrate what I mean:
def xCounter(string): <br>
**counter = 0** (This resets the counter to 0 with each iteration) <br>
if len(string) == 0:
return counter
elif string[0] == 'x':
counter = counter + 1
elif string[0] != 'x':
return xCounter(string[1:],counter)
return xCounter(string[1:],counter)
xCounter("gfljkgfxlkjsfxxljsx")
0
The only way I have it working so far is defining counter as a parameter:
def xCounter(string, counter): <br>
if len(string) == 0: <br>
return counter <br>
elif string[0] == 'x': <br>
counter = counter + 1 <br>
elif string[0] != 'x': <br>
return xCounter(string[1:],counter) <br>
return xCounter(string[1:],counter) <br>
xCounter("werixiuewrxiewx",0)
3
Can anyone please provide me some insight on how to keep count in this function without overwriting the count or defining count as a parameter?

I assume you're doing this for exercise in recursion, not for actual solution, right? The right way to do it in python would be
count = "gfljkgfxlkjsfxxljsx".count('x')
print count
However, you are correct in that your code resets the counter with each iteration, it's supposed to.
There are ways (like global variables) to keep track of the counter without using it as a parameter, but that's BAD BAD BAD. The extra parameter is the way to do it right.

Try this:
def xCounter(string):
if len(string) == 0: return 0
return (string[0]=='x') + xCounter(string[1:])
... if you reach the end of a string, you return 0, otherwise you return 0 or 1 (depending whether string[0] is 'x') plus the function value for the rest of the string... you sum all these numbers in the end and get your answer!
Of course, that's not how it's done, but it's a good practice in recursive functions.
You can even do it shorter, like a lambda:
f=lambda s:len(s) and (s[0]=='x') + f(s[1:]) or 0

Return the recursive call, plus 1 if the character is present. The counter in this case would either be a 0 or a 1; instead of a running total.
You could set a Boolean variable to whether or not the current character is an 'x', then you can change the last line to something like:
return xCounter[1:] +
(if isX then 0 else 1)
The end result will be a chain of addition expressions, where the end result (an addition "chain" of 1s and 0s) is returned.
You could also wrap the "workhorse" function in a wrapper that automatically passes in the initial parameter so the caller doesn't have to:
def xCounter(str):
return xCounterHelper(str, 0)
where xCounterHelper is your original function.
In complicated recursive functions that require more parameters, the second option is very handy. Hide the ugly multi-parameter version as a private function (if it's a class method), and expose the cleaner 1 parameter version (note that Python doesn't have private functions. This is more for languages that do).

Related

recursive way to find if a string is valid

hey so i am trying to write a code that that tells me if a string is valid or not .
a valid string is a string that contains an equal number of "(" and ")" and each "(" must be closed by a ")"
for example
'((()()))' this is a valid string . this isn't ')( '
this is what i wrote so far :
def is_valid_paren(s, cnt=0):
if s == "":
return True
if "(" in s:
cnt += 1
if ")" in s:
cnt -= 1
return is_valid_paren(s[1:])
it doesn't give the correct output for
"(.(a)"
yet for
"p(()r((0)))"
it does
why does it sometimes work ?
oh one more thing this is to be solved only by recursion ( without the use of loops anywhere )
While I don't understand why you want to solve this problem with recursion (it's very unnatural in this case), here is a recursive solution:
def is_valid(s):
def _is_valid(s, idx):
if idx == len(s): return 0
if s[idx] == '(': return _is_valid(s, idx + 1) + 1
if s[idx] == ')': return _is_valid(s, idx + 1) - 1
return _is_valid(s, idx + 1)
return _is_valid(s, 0) == 0
You can pass down a count of pending apertures (i.e. number of unclosed parentheses) and check if the count goes below 0 (too many closures) as you go and if it ends back at zero at the end:
def validPar(s,count=0):
if count<0 : return False # too many closing
if not s: return count == 0 # must balance pending apertures
return validPar(s[1:],count+(-1,1)[s[0]=="("]) # pass down count +/- 1
print(validPar('((()()))')) # True
Recursion
Iteration is likely to be the best method of solving this, but recursion also works. To attack this problem recursively, we need a system of checking the count of each and if at any stage that count falls below zero, the parentheses will be invalid because there are more closing brackets than opening ones. This is where the tough section comes into play: we need some method of not only returning the count, but whether or not the past ones were valid, so we will have to return and save using variables like return count, valid and count, valid = is_valid_parentheses(s[1:]). The next thing we need is some over-arching function which looks at the end results and says: "is the count equal to zero, and were the parentheses valid to begin with". From there, it needs to return the result.

Variable location in recursion

The problem is my code keeps reflecting a variable as zero and this is caused by the fact that the variable is assigned at the start of my function, so each time I call the function the value evaluates to zero. However I need this variable assignment for the code to work and placing it within the elif statements still evaluates to zero and placing the the variable outside the function causes the function not work.
The aim of the program is to count pairs of consecutive letters in a string using recursion with no for/while loops in the code.
def countpairs(s):
pairs=0
if len(s)<2:
return 0 #base case
elif s[0].lower() == s[1].lower(): #recursion
pairs=+1
return countpairs(s[1:])
else: #recursion
pairs=+0
return countpairs(s[1:])
print(countpairs('Hello Salaam'))
This code is supposed to evaluate to 2 because of "ll" and "aa".
You need to wrap your head a little around what the recursion will do: it will call the function recursively to count the pairs from that point on, then (it should) add the pair, if any, found by this instance.
So your function needs to do something with the result of the recursive call, not just return it unchanged. For example, instead of this
elif s[0].lower() == s[1].lower():
pairs = +1
return countpairs(s[1:])
you might write this:
elif s[0].lower() == s[1].lower():
return countpairs(s[1:]) + 1
Something along these lines. You'll need to do a bit more work to get it just right, but I hope you get the idea.
The problems is that the variable pairs resets every recursive call...
When using counting recursive algorithms you don't need a variable that counts, that's the beauty
Instead, try to think how to recursive call can help you count.
def countpairs(s):
if len(s)<2:
return 0
elif s[0].lower() == s[1].lower():
return countpairs(s[1:])+1
else:
return countpairs(s[1:])
print(countpairs('Hello Salaam'))
There you go, in the recursive call the "counter" gets bigger every time it should be, think of the counter as a part of the function stack (or something like that).
You need to fix the syntax: pairs=+1 should be pairs+=1, same for pairs=+0. And you can pass the total into the next level.
def countpairs(s, pairs=0):
if len(s)<2:
return pairs #base case
elif s[0].lower() == s[1].lower(): #recursion
pairs+=1
return countpairs(s[1:], pairs)
else: #recursion
pairs+=0
return countpairs(s[1:], pairs)
print(countpairs('Hello Salaam')) # 2
You can do it by creating a recursive nested function and defining pairs in the outer function. Here's what I mean (with fixes for other issues encountered):
def countpairs(s):
pairs = 0
def _countpairs(s):
nonlocal pairs # Since it's not local nor global.
if len(s) < 2: # base case
return pairs
elif s[0].lower() == s[1].lower():
pairs += 1
return _countpairs(s[1:]) # recursion
else:
return _countpairs(s[1:]) # recursion
return _countpairs(s)
print(countpairs('Hello Salaam')) # -> 2
The code will always evaluate to zero because the last recursion will always have the length of s being less than 2. Instead use the global keyword to be able to grab the value of pairs.
numberOfPairs = 0
pairsList = []
def countpairs(s):
global numberOfPairs
if len(s)<2:
print("doing nothing")
return 0 #base case
elif s[0].lower() == s[1].lower(): #recursion
numberOfPairs+=1
newString = f"{s[0]} is equal to {s[1]}"
print(newString)
pairsList.append(newString)
return countpairs(s[1:])
else:
print(f"nothing happened: {s[0]}") #recursion
return countpairs(s[1:])
print(f"\nThe returned value of countpairs is: {countpairs('Hello Salaam')}")
print(f"Number of pairs: {numberOfPairs}")
print(pairsList)

Python recursion doesn't yield desired result

I am trying to find the length of the string with out using the inbuilt len() function. Here's my python code:
increment = -1
def lenRecur(aStr):
'''
aStr: a string
returns: int, the length of aStr
'''
global increment
if aStr == '':
return increment
else:
increment += 1
return lenRecur (aStr[increment:])
print lenRecur ("abcdefq")
The result I am expecting is 7 but what I got was 4.What I realized was when the increment became 2, the value pass to the lenRecur (aStr[increment:]) was "defq". Which means aStr[2:] is evaluated as "defq" instead of "cdefq".
Why this is happening?
Your function should not depend on external variables.
def lenRecur(aStr):
'''
aStr: a string
returns: int, the length of aStr
'''
if aStr == '':
return 0
else:
return 1 + lenRecur(aStr[1:])
print lenRecur("abcdefq")
A common idiom is to use a default argument:
>>> def l(s, c=0): return l(s[1:], c+1) if s else c
This kind of solution works with anything that can be sliced
>>> l('pip')
3
>>> l([1,2,3])
3
>>> l('')
0
>>> l([])
0
>>>
As an other option, you could write this:
def lenRecur(aStr):
return _lenRecur(aStr, 0)
def _lenRecur(aStr, acc):
if not aStr:
return acc
return _lenRecur(aStr[1:], acc+1)
A noticed by #gboffi in his answer, it is commonly accepted in Python to use a default argument instead of using of an helper function:
def lenRecur(aStr, acc = 0):
if not aStr:
return acc
return lenRecur(aStr[1:], acc+1)
The choice of one form or the other will depend how much you want/don't want to allow the called to set the initial accumulator value to something else than 0.
Anyway, the interesting point here is in using an accumulator as the second parameter. That way, you have proper tail recursion. Unfortunately, this is not properly optimized by Python. But this is a good habit as many other languages have such optimization. And this will be a required skill if you switch someday to functional programing language.

Counting a specific string in the list in Python

I want to count 'fizz' in the list and I wrote below code and it doesn't worked. Tell me why and provide a solution. I was doing this tutorial and I have to write code as their instruction but I am unable to do what they said or maybe I misunderstood them.
count = 0
def fizz_count(x):
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
If you want to check if your answer is correct then you have to check it by interpreting it here. Note that I am not calling my own function. Instead, their is an built in feature in Codecademy tutorial it checks function by calling function with some argument.
You need to have the count variable inside for loop, and you dont require an else condition
def fizz_count(x):
count=0
for string in x:
if string == 'fizz':
count = count + 1
return count
You can also write your function as
def fizz_count(x):
return x.count('fizz')
Have a look at this below code. I made some correction in it. There were some syntactical error and some indentation errors which I fixed it. Have a look at it:
def fizz_count(x):
count = 0
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
str1 = fizz_count(['fizzers','fizzerlss','fizz','fizz'])
print str1
Edit: Same with more explanation due to down votes
Considering your approach with a global variable count (global, because it is not within the function), you would need to do two adaptions:
You need to make count available locally with the keyword global
Since you use a global variable, you do not need to return it because it is available anyway
Code:
count = 0
def fizz_count(x):
global count # make count available for writing in the local scope
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
Now actually using a global variable especially for such kind of tasks is not recommended, because it takes more time to load, you have to take care of the current state and stuff like that, so you rather'd introduce a local variable and pass it via the return statement as you did.
Put count = 0 into function
Code
# we put count = 0 into the function
def fizz_count(x):
count = 0 # right here
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
Now a new count will be initialized to zero within the function.
Now there are two more things here:
the else statement
and the increment
Since the else statement is outside the loop it will be only executed if the if condition was never True during the loop. That has some use cases. But you'd put it in the loop usually. However, in your case it basically does not change anything, thats why it can be removed completely.
Well and the second point is that the increment can be written as count += 1 which is considered more readable, because it is less clumsy and the second count is merged into the +=
Therefore finally the function could be written like so
def fizz_count(x):
count = 0
for string in x:
if string == 'fizz':
count += 1
return count
Check also the reasonable solutions of the other answers

Keeping count in recursive function

I'm trying to figure out how to write a recursive function (with only one parameter) that returns the number of times the substring “ou” appears in the string. Where I'm confused at is that I'm not allowed to use any built-in string functions other than len, or the string operators [] and [:] for indexing and splicing. So I can't use the find built-in find function
I remember seeing something like this, but it uses two parameters and it also uses the find() method
def count_it(target, key):
index = target.find(key)
if index >= 0:
return 1 + count_it(target[index+len(key):], key)
else:
return 0
Very inefficient, but should work:
def count_it(target):
if len(target) < 2:
return 0
else:
return (target[:2] == 'ou') + count_it(target[1:])
See it working online: ideone
It's basically the same idea as the code you posted, except that it moves only one character at a time through the string instead of using find to jump ahead to the next match.
Try this, it works for the general case (any value of key, not only 'ou'):
def count_it(target, key):
if len(target) < len(key):
return 0
found = True
for i in xrange(len(key)):
if target[i] != key[i]:
found = False
break
if found:
return 1 + count_it(target[len(key):], key)
else:
return count_it(target[1:], key)

Categories