Home > Back-end >  Python: Why am I getting TypeErrors on these two problems? (recursion)
Python: Why am I getting TypeErrors on these two problems? (recursion)

Time:10-29

I have two problems that are getting errors that I would like to understand. They are likely for similar reasons, hence why I'm grouping them together in this post. I am here to learn how I can understand solving errors like these!

First, one function aims to find even numbers within a list that contains ints, floats, and strings. For some reason, I get an error that says not all of my arguments were able to convert during string formatting. Here is my code:

def recEvenNumbers(lst):
    'return a count of all the even numbers(ints and floats) in the list'
    evens = 0
    
    if lst == []:
        return
    else:
        if type(lst[0])== int or float:
            if ((lst[0]%2*10))==0:
                evens = evens 1
            return recEvenNumbers(lst[1:], evens   1)

I believe I have this whole function down except this one error. Why is this happening and how can I prevent this in the future?

Another error I am getting is for a different function. Here is the code for that one:

def recMerge(a,b):
    'Merge two strings together recursivly'
    if len(a)==0:
        return
    elif len(b)==0:
        return
    else:
        if type(a) == str:
            if type(b) == str:
                return a[0]   b[0]   recMerge(a[1:], b[1:])

The aim of this function is to merge two strings to create one string that has characters that alternate between each of the two strings. Not really important to my question though, I just want to know why I might be getting a TypeError here. This is what it tells me:

  File "C:/Users/1734/py.py", line 59, in recMerge
    return a[0]   b[0]   recMerge(a[1:], b[1:])
TypeError: can only concatenate str (not "NoneType") to str
>>> 

Why is this happening? I assumed my if type(a) and if type(b) were supposed to handle this. Why can't I use those in this scenario? Or am I just misusing them?

Also, are these two errors related? I know that question may seem strange but if there's a certain element of these questions that I am struggling to understand, I would like to pinpoint what it is and why I am misunderstanding it.

Thanks for your time!

CodePudding user response:

You've committed one of the classic blunders. This statement does not do what you think it does:

        if type(lst[0])== int or float:

This is parsed by Python as:

        if (type(lst[0])== int) or (float):

And since "float" is always true, you will always take the if here. And when lst[0] is a string, the '%' operator is the string formatting operator. You want:

        if type(lst[0]) in (int, float):

or even

        if isinstance(lst[0],int) or isinstance(lst[0],float):

CodePudding user response:

The first function has an error as Tim Roberts described. Additionally, you passed too many arguments to it in the recursive call (and evens will be reset anyway). I recommend looking farther into Python basics to clean that one up.

The second function has a simple mistake. When you say return with nothing else, you will return None. Hence the NoneType error. To fix this, I believe it would suffice to return the empty string ("") instead.

CodePudding user response:

The problem with your second function is that it returns None rather than an empty string for the base case where the input is empty. Since your recursion works by adding onto the result of the recursive call, the very last recursive call must be something you can add to.

def recMerge(a: str, b: str) -> str:
    """Merge two strings together recursively.  If the strings are of
    unequal length, the remainder of the longer string is dropped."""
    # Type check (not necessary if you type-annotate and mypy your code!)
    if not isinstance(a, str) or not isinstance(b, str):
        raise TypeError("both parameters must be strings!")

    # Base case: if one param is empty, there's nothing to merge, so return ""
    if not a or not b:
        return ""

    # Recurse with a smaller slice of both parameters.
    return a[0]   b[0]   recMerge(a[1:], b[1:])

CodePudding user response:

For the first recursive function, this is the correct code

def recEvenNumbers(lst, evens):
    if not lst:
        return evens

    if type(lst[0]) == int:
        if(lst[0]%2 == 0):
            return recEvenNumbers(lst[1:], evens   1)
        else:
            return recEvenNumbers(lst[1:], evens)
    else:
        return recEvenNumbers(lst[1:], evens)

x = recEvenNumbers([1, 2, 3, 4, 5.3, 7, 8, "h", 46, "32"], 0)
print(x)

It is important to return when you're writing a recursive function, otherwise, you get "None". When you're calling to a function make sure to add every parameter ex:(last, evens).

CodePudding user response:

I know everyone else is commenting your first problem, but it works if you work it right. That said, you should handle the string first and add evens as a None parameter to check on instance for the first pass.

Here's a working function:

def recEvenNumbers(lst, evens = None):
    'return a count of all the even numbers(ints and floats) in the list'
    if evens is None:
        evens = [0]

    if lst:
        # To keep things organized, extract first item
        # into variable and the rest into a smaller list with
        # star selection
        item, *lst = lst

        # Check for string first
        # Pass rest of process if detected.
        if type(item) == str:
            pass
        # Continue as you were before
        elif type(item) == int or float:
            if item % 2 * 10 == 0:
                evens[0]  = 1

        # Recurse with appropriate params.
        return recEvenNumbers(lst, evens)
    # Return result.
    return evens[0]

Run the function:

test_list = [1, 2.2, 4, "string"]
recEvenNumbers(test_list)

Output:

1

Part 2:

# Function with commentary.
def recMerge(a, b):
    'Merge two strings together recursivly'
    # Check types
    if type(a) == type(b) == str:
        # Run until b is empty.
        if len(b) > 0:
            # Deconstructing into single and rest of items with asterisk.
            aa, *a_rest = a
            bb, *b_rest = b
            # New `a` value that prepends the rest of a in
            # front of the concatenation of the current a and b characters.
            # Since a_rest is a list, we should "collect" the items back into
            # a proper string format.
            a = "".join(a_rest)   aa   bb
            # Return the new a with another concatenated list for the
            # remaining b items.
            return recMerge(a, "".join(b_rest))
    # Return a.  Ensure that it is a string.
    return "".join(a)

Run test case:

A = "abc"
B = "def"
recMerge(A, B)

Output:

'adbecf'
  • Related