Quantcast
Channel: Python - The Collatz Sequence - Code Review Stack Exchange
Viewing all articles
Browse latest Browse all 4

Answer by Carcigenicate for Python - The Collatz Sequence

$
0
0

First, note how you're duplicating calculations:

print(num//2)num = num //2

This may not cause issues with this specific code, but it isn't a good practice. You're doing twice as much work as you need to, which can cause performance issues once you start writing more complicated code. Do the calculation once, and save the result. In this case though, all you need to do is reverse those lines and use num:

num = num // 2print(num)

Also, make sure you have proper spacing around operators, and be consistent.


Your if and elif cases are exclusive of each other, and your else should never happen. If the first condition is true, then other must be false and vice-versa. There's no need for the second check. Once rewritten, you'll see that printing in every case isn't necessary. You can just print after:

while num > 1:    if num % 2 == 0:        num = num // 2    else:        num = 3 * num + 1    print(num)

Since you're just reassinging num one of two options based on a condition, a conditional expression can be used here cleanly as well:

while num > 1:    num = (num // 2) if num % 2 == 0 else (3 * num + 1)    print(num)

The braces aren't necessary, but I think they're useful here due to the number of operators involved.



Printing the numbers isn't ideal here. In most code, you need to be able to use the data that you produce. If you wanted to analyze the produced sequence, you would have to do something intercept the stdout, which is expensive and overly complicated. Make it a function that accumulates and returns a list. In the following examples, I also added some type hints to make it clearer what the type of the data is:

from typing import Listdef collatz(starting_num: int) -> List[int]:    nums = [starting_num]    num = starting_num    while num > 1:        num = (num // 2) if num % 2 == 0 else (3 * num + 1)        nums.append(num)    return nums

Or, a much cleaner approach is to make it a generator that yields the numbers:

# Calling this function returns a generator that produces ints# Ignore the two Nones, as they aren't needed for this kind of generatordef collatz_gen(starting_num: int) -> Generator[int, None, None]:    yield starting_num    num = starting_num    while num > 1:        num = (num // 2) if num % 2 == 0 else (3 * num + 1)        yield num>>> list(collatz_gen(5))[5, 16, 8, 4, 2, 1]


There's a few notable things about getNum:

Python uses "snake_case", not "camelCase".


Your use of global num here is unnecessary and confusing. Just like before, explicitly return any data that the function produces:

def get_num() -> int:    raw_num = input("> ")    try:        return int(raw_num)    except ValueError:        print('Please enter a number')        return get_num()

Note how instead of reassigning a global num, we're just returning the number. I also spaced things out a bit, and used some more appropriate names. Conceptually, I'd say that num = input("> ") is wrong. At the time that that runs, num does not contain a number (it contains a string).


This isn't a good use of recursion. It likely won't cause you any problems, but if your user is really dumb and enters wrong data ~1000 times, your program will crash. Just use a loop:

def get_num() -> int:    while True:        raw_num = input("> ")        try:            return int(raw_num)        except ValueError:            print('Please enter a number')

In languages like Python, be careful using recursion in cases where you have no guarantees about how many times the function will recurse.


I'd also probably name this something closer to ask_for_num. "get" doesn't make it very clear about where the data is coming from.



Taken altogether, you'll end up with:

from typing import Generatordef collatz_gen(starting_num: int) -> Generator[int, None, None]:    yield starting_num    num = starting_num    while num > 1:        num = (num // 2) if num % 2 == 0 else (3 * num + 1)        yield numdef ask_for_num() -> int:    while True:        raw_num = input("> ")        try:            return int(raw_num)        except ValueError:            print('Please enter a number')

Which can be used like:

num = ask_for_num()for n in collatz_gen(num):    print(n)

Viewing all articles
Browse latest Browse all 4

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>