How can I shorten a function which outputs the chain numbers of the Collatz conjecture?

Question:

This Python function outputs a list based on the collatz conjecture. This is an unsolved maths problem where the function will perform different operations on ‘n’ depending on if it is odd or even, outputting ‘n’ to a list called ‘seq’ each time the function repeats. Eventually ‘n’ will decay to the end point (‘1′) once the number ’16’ appears in the ‘chain’.

I am trying to make the code as concise as possible here. Is there any way to shorten the function?

This is my newbie Python code:

def collatz(n):

    seq = []
    n = int(n)

    if n == 0:
        return 
    
    elif n == 1:
        return seq + [n]
    
    elif n > 1 == True and n % 2 == 0:
        return seq + [n] + collatz(n/2)
    
    else:
        return seq + [n] + collatz(3*n+1)

print(collatz(7))

this outputs

[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
Asked By: Alastair909

||

Answers:

As of right now, the function you gave isn’t fully robust for negative inputs and 0: I would rewrite it as such below. I think yours is very readable though, and I wouldn’t promote more conciseness: readability > conciseness almost always.

def collatz(n):

    seq = []
    n = int(n)

    if n <= 0:
        return False
    
    elif n == 1:
        return seq + [n]
    
    elif n % 2 == 0:
        return seq + [n] + collatz(n/2)
    
    else:
        return seq + [n] + collatz(3*n+1)

print(collatz(7))

If you really want more concise code, consider this solution by @Kelly Bundy:

def collatz(n):
    return [1] if n == 1 else [n] + collatz(3*n+1 if n%2 else n//2)

print(collatz(7))

Alternatively, an iterative rather than recursive solution

def collatz(n):
    seq = [n]
    while n != 1:
        n = 3*n+1 if n%2 else n//2
        seq.append(n)
    return seq

Sanitise your inputs as you wish.

Answered By: Jakub Skop

I’ve got issues with the more readable version of the currently selected answer. First, there’s no need for the else and elif statements given the return statements.

Second, I wouldn’t endorse a function that returns a boolean sometimes and a list otherwise. The return type should be consistent:

def collatz(n):
    if n <= 0:
        return []

    if n == 1:
        return [n]

    if n % 2:
        return [n, *collatz(3 * n + 1)]

    return [n, *collatz(n // 2)]

print(collatz(7))
Answered By: cdlane