Python - The Collatz SequenceProject Euler #14 (Longest Collatz sequence)Project Euler #14 — longest...

What is the most damaging one handed melee weapon?

Circle divided by lines between a blue dots

GitHub repo with Apache License version 2 in package.json, but no full license copy nor comment headers

What do these pins mean? Where should I plug them in?

Can the U.S. president make military decisions without consulting anyone?

How to deal with my team leader who keeps calling me about project updates even though I am on leave for personal reasons?

Can planetary bodies have a second axis of rotation?

I reverse the source code, you negate the output!

What was an "insurance cover"?

What was the deeper meaning of Hermione wanting the cloak?

How to reference parameters outside of Apex Class that can be configured by Administrator

Minimize taxes now that I earn more

Pandas aggregate with dynamic column names

Can someone explain to me the parameters of a lognormal distribution?

Can one guy with a duplicator initiate a nuclear apocalypse?

Why are some of the Stunts in The Expanse RPG labelled 'Core'?

Repeat elements in list, but the number of times each element is repeated is provided by a separate list

Was there a trial by combat between a man and a dog in medieval France?

CDG baggage claim before or after immigration?

Cheap antenna for new HF HAM

Resolving moral conflict

Applications of mathematics in clinical setting

Should the pagination be reset when changing the order?

If water is incompressible, how can sound propagate underwater?



Python - The Collatz Sequence


Project Euler #14 (Longest Collatz sequence)Project Euler #14 — longest Collatz sequenceHailstone Sequences in PythonPython program for testing the Collatz ConjectureProject Euler: Longest Collatz SequenceCounting terms in Collatz sequences until 1 is reached or a limit is exceededAutomate the Boring Stuff - Collatz ExerciseComputational verification of Collatz conjecture






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







5












$begingroup$


Can I get a review of my code for the the Collatz Sequence from Chapter three of Automate the Boring Stuff with Python?




The Collatz Sequence



Write a function named collatz() that has one parameter named number.
If number is even, then collatz() should print number // 2 and return
this value. If number is odd, then collatz() should print and return 3
* number + 1.



Then write a program that lets the user type in an integer and that
keeps calling collatz() on that number until the function returns the
value 1. (Amazingly enough, this sequence actually works for any
integer—sooner or later, using this sequence, you’ll arrive at 1! Even
mathematicians aren’t sure why. Your program is exploring what’s
called the Collatz sequence, sometimes called “the simplest impossible
math problem.”)



Remember to convert the return value from input() to an integer with
the int() function; otherwise, it will be a string value.



Hint: An integer number is even if number % 2 == 0, and it’s odd if
number % 2 == 1.



The output of this program could look something like this:



Enter number:
3
10
5
16
8
4
2
1


Input Validation



Add try and except statements to the previous project to detect
whether the user types in a noninteger string. Normally, the int()
function will raise a ValueError error if it is passed a noninteger
string, as in int('puppy'). In the except clause, print a message to
the user saying they must enter an integer.




I am mainly wondering if there is a cleaner way to write my solution.



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

def getNum():
global num
num = (input("> "))
try:
num = int(num)
except ValueError:
print('plese enter a number')
getNum()
getNum()
collatz(num)









share|improve this question









New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$










  • 2




    $begingroup$
    Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
    $endgroup$
    – Emad Boctor
    8 hours ago










  • $begingroup$
    @Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
    $endgroup$
    – cyberprogrammer
    8 hours ago


















5












$begingroup$


Can I get a review of my code for the the Collatz Sequence from Chapter three of Automate the Boring Stuff with Python?




The Collatz Sequence



Write a function named collatz() that has one parameter named number.
If number is even, then collatz() should print number // 2 and return
this value. If number is odd, then collatz() should print and return 3
* number + 1.



Then write a program that lets the user type in an integer and that
keeps calling collatz() on that number until the function returns the
value 1. (Amazingly enough, this sequence actually works for any
integer—sooner or later, using this sequence, you’ll arrive at 1! Even
mathematicians aren’t sure why. Your program is exploring what’s
called the Collatz sequence, sometimes called “the simplest impossible
math problem.”)



Remember to convert the return value from input() to an integer with
the int() function; otherwise, it will be a string value.



Hint: An integer number is even if number % 2 == 0, and it’s odd if
number % 2 == 1.



The output of this program could look something like this:



Enter number:
3
10
5
16
8
4
2
1


Input Validation



Add try and except statements to the previous project to detect
whether the user types in a noninteger string. Normally, the int()
function will raise a ValueError error if it is passed a noninteger
string, as in int('puppy'). In the except clause, print a message to
the user saying they must enter an integer.




I am mainly wondering if there is a cleaner way to write my solution.



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

def getNum():
global num
num = (input("> "))
try:
num = int(num)
except ValueError:
print('plese enter a number')
getNum()
getNum()
collatz(num)









share|improve this question









New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$










  • 2




    $begingroup$
    Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
    $endgroup$
    – Emad Boctor
    8 hours ago










  • $begingroup$
    @Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
    $endgroup$
    – cyberprogrammer
    8 hours ago














5












5








5





$begingroup$


Can I get a review of my code for the the Collatz Sequence from Chapter three of Automate the Boring Stuff with Python?




The Collatz Sequence



Write a function named collatz() that has one parameter named number.
If number is even, then collatz() should print number // 2 and return
this value. If number is odd, then collatz() should print and return 3
* number + 1.



Then write a program that lets the user type in an integer and that
keeps calling collatz() on that number until the function returns the
value 1. (Amazingly enough, this sequence actually works for any
integer—sooner or later, using this sequence, you’ll arrive at 1! Even
mathematicians aren’t sure why. Your program is exploring what’s
called the Collatz sequence, sometimes called “the simplest impossible
math problem.”)



Remember to convert the return value from input() to an integer with
the int() function; otherwise, it will be a string value.



Hint: An integer number is even if number % 2 == 0, and it’s odd if
number % 2 == 1.



The output of this program could look something like this:



Enter number:
3
10
5
16
8
4
2
1


Input Validation



Add try and except statements to the previous project to detect
whether the user types in a noninteger string. Normally, the int()
function will raise a ValueError error if it is passed a noninteger
string, as in int('puppy'). In the except clause, print a message to
the user saying they must enter an integer.




I am mainly wondering if there is a cleaner way to write my solution.



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

def getNum():
global num
num = (input("> "))
try:
num = int(num)
except ValueError:
print('plese enter a number')
getNum()
getNum()
collatz(num)









share|improve this question









New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$




Can I get a review of my code for the the Collatz Sequence from Chapter three of Automate the Boring Stuff with Python?




The Collatz Sequence



Write a function named collatz() that has one parameter named number.
If number is even, then collatz() should print number // 2 and return
this value. If number is odd, then collatz() should print and return 3
* number + 1.



Then write a program that lets the user type in an integer and that
keeps calling collatz() on that number until the function returns the
value 1. (Amazingly enough, this sequence actually works for any
integer—sooner or later, using this sequence, you’ll arrive at 1! Even
mathematicians aren’t sure why. Your program is exploring what’s
called the Collatz sequence, sometimes called “the simplest impossible
math problem.”)



Remember to convert the return value from input() to an integer with
the int() function; otherwise, it will be a string value.



Hint: An integer number is even if number % 2 == 0, and it’s odd if
number % 2 == 1.



The output of this program could look something like this:



Enter number:
3
10
5
16
8
4
2
1


Input Validation



Add try and except statements to the previous project to detect
whether the user types in a noninteger string. Normally, the int()
function will raise a ValueError error if it is passed a noninteger
string, as in int('puppy'). In the except clause, print a message to
the user saying they must enter an integer.




I am mainly wondering if there is a cleaner way to write my solution.



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

def getNum():
global num
num = (input("> "))
try:
num = int(num)
except ValueError:
print('plese enter a number')
getNum()
getNum()
collatz(num)






python collatz-sequence






share|improve this question









New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










share|improve this question









New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








share|improve this question




share|improve this question








edited 7 hours ago









200_success

136k21 gold badges175 silver badges445 bronze badges




136k21 gold badges175 silver badges445 bronze badges






New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








asked 9 hours ago









cyberprogrammercyberprogrammer

266 bronze badges




266 bronze badges




New contributor



cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




New contributor




cyberprogrammer is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.













  • 2




    $begingroup$
    Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
    $endgroup$
    – Emad Boctor
    8 hours ago










  • $begingroup$
    @Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
    $endgroup$
    – cyberprogrammer
    8 hours ago














  • 2




    $begingroup$
    Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
    $endgroup$
    – Emad Boctor
    8 hours ago










  • $begingroup$
    @Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
    $endgroup$
    – cyberprogrammer
    8 hours ago








2




2




$begingroup$
Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
$endgroup$
– Emad Boctor
8 hours ago




$begingroup$
Please add some description indicating what this chapter 3 thing is recommending with examples of input and output, nobody's going to guess what that is
$endgroup$
– Emad Boctor
8 hours ago












$begingroup$
@Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
$endgroup$
– cyberprogrammer
8 hours ago




$begingroup$
@Edmad Broctor and @ Carcigenicate Thanks for your feedback. I went ahead and revised my post.
$endgroup$
– cyberprogrammer
8 hours ago










2 Answers
2






active

oldest

votes


















6














$begingroup$

Prompt



The most obvious bad practice here is the use of a global variable. Instead of setting num as a side-effect, your function should return the result.



getNum() is not such a good name for the function. PEP 8, the official style guide for Python, says that function names should be lower_case_with_underscores. Furthermore, "get" implies that the function is retrieving a piece of data that is already stored somewhere, which is not the case here. Finally, "Num" should be more specific.



The use of recursion is not appropriate. If you want a loop, write a loop.



def ask_integer():
"""
Return an integer entered by the user (repeatedly prompting if
the input is not a valid integer).
"""
while True:
try:
return int(input("> "))
except ValueError:
print("Please enter an integer")

num = ask_integer()



collatz function



Strictly speaking, you didn't follow the instructions. Your solution isn't wrong or bad — you just didn't implement the collatz function according to the specification that was given, which says that you should print and return one single number.



def collatz(num):
"""
Given a number, print and return its successor in the Collatz sequence.
"""
next = num // 2 if num % 2 == 0 else 3 * num + 1
print(next)
return next

num = ask_integer()
while num > 1:
num = collatz(num)





share|improve this answer









$endgroup$















  • $begingroup$
    Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
    $endgroup$
    – RootTwo
    6 hours ago










  • $begingroup$
    @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
    $endgroup$
    – Carcigenicate
    4 hours ago



















4














$begingroup$

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 // 2
print(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 List

def 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 generator
def 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 Generator

def 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

def 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)





share|improve this answer











$endgroup$


















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "196"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });







    cyberprogrammer is a new contributor. Be nice, and check out our Code of Conduct.










    draft saved

    draft discarded
















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229270%2fpython-the-collatz-sequence%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    6














    $begingroup$

    Prompt



    The most obvious bad practice here is the use of a global variable. Instead of setting num as a side-effect, your function should return the result.



    getNum() is not such a good name for the function. PEP 8, the official style guide for Python, says that function names should be lower_case_with_underscores. Furthermore, "get" implies that the function is retrieving a piece of data that is already stored somewhere, which is not the case here. Finally, "Num" should be more specific.



    The use of recursion is not appropriate. If you want a loop, write a loop.



    def ask_integer():
    """
    Return an integer entered by the user (repeatedly prompting if
    the input is not a valid integer).
    """
    while True:
    try:
    return int(input("> "))
    except ValueError:
    print("Please enter an integer")

    num = ask_integer()



    collatz function



    Strictly speaking, you didn't follow the instructions. Your solution isn't wrong or bad — you just didn't implement the collatz function according to the specification that was given, which says that you should print and return one single number.



    def collatz(num):
    """
    Given a number, print and return its successor in the Collatz sequence.
    """
    next = num // 2 if num % 2 == 0 else 3 * num + 1
    print(next)
    return next

    num = ask_integer()
    while num > 1:
    num = collatz(num)





    share|improve this answer









    $endgroup$















    • $begingroup$
      Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
      $endgroup$
      – RootTwo
      6 hours ago










    • $begingroup$
      @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
      $endgroup$
      – Carcigenicate
      4 hours ago
















    6














    $begingroup$

    Prompt



    The most obvious bad practice here is the use of a global variable. Instead of setting num as a side-effect, your function should return the result.



    getNum() is not such a good name for the function. PEP 8, the official style guide for Python, says that function names should be lower_case_with_underscores. Furthermore, "get" implies that the function is retrieving a piece of data that is already stored somewhere, which is not the case here. Finally, "Num" should be more specific.



    The use of recursion is not appropriate. If you want a loop, write a loop.



    def ask_integer():
    """
    Return an integer entered by the user (repeatedly prompting if
    the input is not a valid integer).
    """
    while True:
    try:
    return int(input("> "))
    except ValueError:
    print("Please enter an integer")

    num = ask_integer()



    collatz function



    Strictly speaking, you didn't follow the instructions. Your solution isn't wrong or bad — you just didn't implement the collatz function according to the specification that was given, which says that you should print and return one single number.



    def collatz(num):
    """
    Given a number, print and return its successor in the Collatz sequence.
    """
    next = num // 2 if num % 2 == 0 else 3 * num + 1
    print(next)
    return next

    num = ask_integer()
    while num > 1:
    num = collatz(num)





    share|improve this answer









    $endgroup$















    • $begingroup$
      Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
      $endgroup$
      – RootTwo
      6 hours ago










    • $begingroup$
      @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
      $endgroup$
      – Carcigenicate
      4 hours ago














    6














    6










    6







    $begingroup$

    Prompt



    The most obvious bad practice here is the use of a global variable. Instead of setting num as a side-effect, your function should return the result.



    getNum() is not such a good name for the function. PEP 8, the official style guide for Python, says that function names should be lower_case_with_underscores. Furthermore, "get" implies that the function is retrieving a piece of data that is already stored somewhere, which is not the case here. Finally, "Num" should be more specific.



    The use of recursion is not appropriate. If you want a loop, write a loop.



    def ask_integer():
    """
    Return an integer entered by the user (repeatedly prompting if
    the input is not a valid integer).
    """
    while True:
    try:
    return int(input("> "))
    except ValueError:
    print("Please enter an integer")

    num = ask_integer()



    collatz function



    Strictly speaking, you didn't follow the instructions. Your solution isn't wrong or bad — you just didn't implement the collatz function according to the specification that was given, which says that you should print and return one single number.



    def collatz(num):
    """
    Given a number, print and return its successor in the Collatz sequence.
    """
    next = num // 2 if num % 2 == 0 else 3 * num + 1
    print(next)
    return next

    num = ask_integer()
    while num > 1:
    num = collatz(num)





    share|improve this answer









    $endgroup$



    Prompt



    The most obvious bad practice here is the use of a global variable. Instead of setting num as a side-effect, your function should return the result.



    getNum() is not such a good name for the function. PEP 8, the official style guide for Python, says that function names should be lower_case_with_underscores. Furthermore, "get" implies that the function is retrieving a piece of data that is already stored somewhere, which is not the case here. Finally, "Num" should be more specific.



    The use of recursion is not appropriate. If you want a loop, write a loop.



    def ask_integer():
    """
    Return an integer entered by the user (repeatedly prompting if
    the input is not a valid integer).
    """
    while True:
    try:
    return int(input("> "))
    except ValueError:
    print("Please enter an integer")

    num = ask_integer()



    collatz function



    Strictly speaking, you didn't follow the instructions. Your solution isn't wrong or bad — you just didn't implement the collatz function according to the specification that was given, which says that you should print and return one single number.



    def collatz(num):
    """
    Given a number, print and return its successor in the Collatz sequence.
    """
    next = num // 2 if num % 2 == 0 else 3 * num + 1
    print(next)
    return next

    num = ask_integer()
    while num > 1:
    num = collatz(num)






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 7 hours ago









    200_success200_success

    136k21 gold badges175 silver badges445 bronze badges




    136k21 gold badges175 silver badges445 bronze badges















    • $begingroup$
      Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
      $endgroup$
      – RootTwo
      6 hours ago










    • $begingroup$
      @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
      $endgroup$
      – Carcigenicate
      4 hours ago


















    • $begingroup$
      Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
      $endgroup$
      – RootTwo
      6 hours ago










    • $begingroup$
      @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
      $endgroup$
      – Carcigenicate
      4 hours ago
















    $begingroup$
    Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
    $endgroup$
    – RootTwo
    6 hours ago




    $begingroup$
    Perhaps reverse the test and eliminate the comparison to 0: next = 3 * num + 1 if num % 2 else num // 2
    $endgroup$
    – RootTwo
    6 hours ago












    $begingroup$
    @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
    $endgroup$
    – Carcigenicate
    4 hours ago




    $begingroup$
    @RootTwo Honestly, I find that that muddies the intent. We're not checking if num % 2 is falsey; it's not a predicate. We're checking if it's equal to 0. It just so happens that they're equivalent in Python.
    $endgroup$
    – Carcigenicate
    4 hours ago













    4














    $begingroup$

    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 // 2
    print(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 List

    def 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 generator
    def 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 Generator

    def 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

    def 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)





    share|improve this answer











    $endgroup$




















      4














      $begingroup$

      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 // 2
      print(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 List

      def 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 generator
      def 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 Generator

      def 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

      def 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)





      share|improve this answer











      $endgroup$


















        4














        4










        4







        $begingroup$

        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 // 2
        print(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 List

        def 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 generator
        def 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 Generator

        def 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

        def 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)





        share|improve this answer











        $endgroup$



        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 // 2
        print(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 List

        def 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 generator
        def 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 Generator

        def 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

        def 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)






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 7 hours ago

























        answered 8 hours ago









        CarcigenicateCarcigenicate

        7,2341 gold badge19 silver badges46 bronze badges




        7,2341 gold badge19 silver badges46 bronze badges


























            cyberprogrammer is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded

















            cyberprogrammer is a new contributor. Be nice, and check out our Code of Conduct.













            cyberprogrammer is a new contributor. Be nice, and check out our Code of Conduct.












            cyberprogrammer is a new contributor. Be nice, and check out our Code of Conduct.
















            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f229270%2fpython-the-collatz-sequence%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Taj Mahal Inhaltsverzeichnis Aufbau | Geschichte | 350-Jahr-Feier | Heutige Bedeutung | Siehe auch |...

            Baia Sprie Cuprins Etimologie | Istorie | Demografie | Politică și administrație | Arii naturale...

            Nicolae Petrescu-Găină Cuprins Biografie | Opera | In memoriam | Varia | Controverse, incertitudini...