Search code examples
pythonrecursion

Why does my function not work if I use recursion inside the if statement


I was trying to create a function that returns a list without any repetition using recursion, but I found something intriguing.

When I write the code like this:

def norep(xs):
    if len(xs) == 0:
        return xs
    if xs[0] in norep(xs[1:]):
        return xs[1:]
    else:
        return xs


l = norep([1, 2, 33, 4, 5, 2, 1, 24, 34, 2, 3, 5])
print(l)

the code returns this:

[2, 33, 4, 5, 2, 1, 24, 34, 2, 3, 5]

When I write it like this:

def norep(xs):
    if len(xs) == 0:
        return xs
    if xs[0] in xs[1:]:
        return norep(xs[1:])
    else:
        return [xs[0]] + norep(xs[1:])


l = norep([1, 2, 33, 4, 5, 2, 1, 24, 34, 2, 3, 5])
print(l)

it returns the expected output:

[33, 4, 1, 24, 34, 2, 3, 5]

Why doesn't the first code work, but the second one does?


Solution

  • This bit of code:

        if xs[0] in xs[1:]:
            return norep(xs[1:])
    

    Does the following:

    • evaluate xs[0] in xs[1:]
    • to do so, it evaluates xs[0] (some value), evaluates xs[1:] (some other value), and the resulting value of the evaluation is a boolean representing whether the first value is in the second value (however that's defined for those values).
    • if the result of the evaluation is True, runs the next line.
    • the next line evaluates norep(xs[1:]) and will return the outcome as the return value of the function
    • to do so, it evaluates xs[1:], and passes the result to norep() as the first argument.

    So, if xs[0] in xs[1:], the return value of the recursive call will be returned.

    However, this bit of code:

        if xs[0] in norep(xs[1:]):
            return xs[1:]
    

    Does the following:

    • evaluate xs[0] in norep(xs[1:])
    • to do so, it evaluates xs[0] (some value), then evaluates norep(xs[1:]) etc.
    • however, evaluating norep(xs[1:]) means it evaluates xs[1:], and passes the result to norep() as the first argument
    • if xs[0] is in the return value of that function call, runs the next line
    • that simply returns the value of xs[1:].

    So, in both cases, the function is called recursively. But in the first example, the return value of the recursive call is returned. In the second example, the return value is always xs[1:].

    In the else part, xs is returned, so no return value of the second example's function ever includes the return value of the recursive call.