Python - The Collatz SequenceProject 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
Can planetary bodies have a second axis of rotation?
How do rulers get rich from war?
Is there an in-universe reason Harry says this or is this simply a Rowling mistake?
Asking an expert in your field that you have never met to review your manuscript
Gas leaking in base of new gas range?
Norwegian refuses EU delay (4.7 hours) compensation because it turned out there was nothing wrong with the aircraft
Repeat elements in list, but the number of times each element is repeated is provided by a separate list
How to create a grid following points in QGIS?
Social leper versus social leopard
Where Does VDD+0.3V Input Limit Come From on IC chips?
In a jam session, when asked which key my non-transposing instrument (like a violin) is in, what do I answer?
Hiking with a mule or two?
Pseudo Game of Cups in Python
What can a pilot do if an air traffic controller is incapacitated?
Can Northern Ireland's border issue be solved by repartition?
Nanomachines exist that enable Axolotl-levels of regeneration - So how can crippling injuries exist as well?
How to reference parameters outside of Apex Class that can be configured by Administrator
US entry with tourist visa but past alcohol arrest
How does one calculate the distribution of the Matt Colville way of rolling stats?
Minimize taxes now that I earn more
How do I extract code from an arduino?
Hilbert's hotel, why can't I repeat it infinitely many times?
Cheap antenna for new HF HAM
How could artificial intelligence harm us?
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;
$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)
python collatz-sequence
New contributor
$endgroup$
add a comment
|
$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)
python collatz-sequence
New contributor
$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
add a comment
|
$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)
python collatz-sequence
New contributor
$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
python collatz-sequence
New contributor
New contributor
edited 7 hours ago
200_success
136k21 gold badges175 silver badges445 bronze badges
136k21 gold badges175 silver badges445 bronze badges
New contributor
asked 8 hours ago
cyberprogrammercyberprogrammer
266 bronze badges
266 bronze badges
New contributor
New contributor
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
add a comment
|
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
add a comment
|
2 Answers
2
active
oldest
votes
$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)
$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 ifnum % 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
add a comment
|
$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)
$endgroup$
add a comment
|
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
$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)
$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 ifnum % 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
add a comment
|
$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)
$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 ifnum % 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
add a comment
|
$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)
$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)
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 ifnum % 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
add a comment
|
$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 ifnum % 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
add a comment
|
$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)
$endgroup$
add a comment
|
$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)
$endgroup$
add a comment
|
$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)
$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)
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
add a comment
|
add a comment
|
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.
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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