9
def count_m_recursive(sentence):
    s = len(sentence) 
    if s == 0:
        return 0
    elif sentence[0] == 'm':
        return 1
    else:
        return count_m_recursive(sentence[1:s-1]

This is my code. So if count_m_recursive('my oh my') I should get 2

What is wrong with the code ?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3398505
  • 607
  • 1
  • 7
  • 13
  • 2
    How on earth do you expect that code to return `2`? I mean.... *there is not even a sum there*! That function always and *only* returns `0` or `1`. – Bakuriu Apr 09 '14 at 16:16

4 Answers4

20

Two things are wrong:

  1. You are cutting off the last character on each recursive call:

    return count_m_recursive(sentence[1:s-1])
    

    Don't limit the call to s-1, the end index is not included.

  2. You don't want to ignore the rest of the text when you find an m at the start; your version returns 1 and ignores the rest of the string.

Your function works with:

elif sentence[0] == 'm':
    return 1 + count_m_recursive(sentence[1:])
else:
    return count_m_recursive(sentence[1:])

or, simplified:

def count_m_recursive(sentence):
    if not sentence:  # an empty string tests false
        return 0
    return (1 if sentence[0] == 'm' else 0) + count_m_recursive(sentence[1:])

or even use the fact that bool is a subclass of int and True is 1, False is 0:

def count_m_recursive(sentence):
    if not sentence:  # an empty string tests false
        return 0
    return (sentence[0] == 'm') + count_m_recursive(sentence[1:])

Demo:

>>> def count_m_recursive(sentence):
...     if not sentence:  # an empty string tests false
...         return 0
...     return (sentence[0] == 'm') + count_m_recursive(sentence[1:])
... 
>>> count_m_recursive('my oh my')
2
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
12

For the fun, you can write the entire thing as an anonymous lambda expression as follows:

def make_funny_func():
    # wrapped the code with return clause to emphasize that it is 
    # anonymous ;)
    return (
        # Y combinator
        (lambda f: (lambda x: x(x))(lambda y: f(lambda a: y(y)(a))))
        # our function wrapped
        (lambda count:
            lambda s:
                # return 1 + f(s[1:]) if the first character is 'm'
                # 0 + f(s[1:]) otherwise.
                (s[0] == 'm') + count(s[1:])
                # but do the thing before only if s is non-empty string
                if s
                # else return 0
                else 0
        )
    )

count_m_recursive = make_funny_func()
print(count_m_recursive('mmmkay'))

Peer pessure badge, here we come ;-)

6
def count_m_recursive(sentence): #mmmm
    if not sentence:
        return 0
    m_first = 1 if sentence[0] == 'm' else 0
    return m_first + count_m_recursive(sentence[1:])

To outline some issues in current implementation:

  1. No need to calculate length of a string to check if it's empty. Empty strings are equivivalent to False in boolean "context" (e.g. not s is true if s is empty or None)
  2. You don't sum up occurences of the m in a string, so there should be some count_so_far + recursive_call(). In your case, since you examine string char by char count_so_far is 1 if current char is m, 0 otherwise.
  3. Proper slicing to get the all the string except first N chars would be string[N:]. There's a good explanation of slicing on SO

Also, this is a perfect example of tail recursive algorithm. Such kinds of algorithms can be expressed as a loop with advantage of executing in one call stack frame. Note that a lot of compilers optimize tail recursion to loop anyway (but that's not true for python interpreter).

Community
  • 1
  • 1
J0HN
  • 26,063
  • 5
  • 54
  • 85
  • 3
    Python does not optimize tail recursion; you'd explicitly use a loop instead. The dynamic nature of Python prevents optimization (the code could self-alter in more ways than I could count). – Martijn Pieters Apr 09 '14 at 09:46
  • But in my experience this is homework; the OP is asked to write a recursive function to learn about recursive programming, not to optimize away the recursion, at least *not yet*. :-) – Martijn Pieters Apr 09 '14 at 09:48
  • @MartijnPieters I'm not familiar with intrinsics of CPython to confidently state anything about optimizations it can or can't do, but I think I can trust your word on it. And I think I put this note on the wrong list, it shouldn't be seen as "issue", it's more of a general fact. – J0HN Apr 09 '14 at 10:25
1

Problem is with

  1. elif sentence[0] == 'm':
  2. slicing off last char with sentence[1:-1]

// Note Boolean is derived class of integer class

def count_m_recursive(sentence):
    return (sentence or 0 ) and ((sentence[0] == 'm') + count_m_recursive(sentence[1:]))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Arovit
  • 3,579
  • 5
  • 20
  • 24