Python: Help, function not producing what I want - python

I'm trying to make a collatz sequence that'll print out the numbers continuously as I input the initial integer until it reaches 1 but it's not working quite well.
def collatz():
try:
number = int(input("Please enter a number: "))
except ValueError:
collatz()
while number != 1:
if number%2 == 0:
print(number // 2)
else:
print(3 * number + 1)
This is what I created and it only returns the value of a single calculation
>>> collatz()
Please enter a number: 45
136
>>> collatz()
Please enter a number: 8
4
I don't quite understand why this is happening when I want the calculation to go on and keep printing values till it gets to 1(it will always get to 1 that's the trick of the sequence).

You never assign any new value to number, so the while loop is forever True.
Calculate the new value, assign it back to number, then print that new value:
while number != 1:
if number % 2 == 0:
number //= 2
else:
number = 3 * number + 1
print(number)
Note that you should not use recursion to get a valid input; use a while loop instead. In your case, when the recursive function exits and returns, the code would then go on to the while loop with number unbound, resulting in an UnboundLocal exception.
I'd put asking for the number outside the function, perhaps in a new function:
def collatz(number):
while number != 1:
if number % 2 == 0:
number //= 2
else:
number = 3 * number + 1
print(number)
def ask_for_number():
while True:
try:
return int(input("Please enter a number: "))
except ValueError:
print("That's not a valid number, please try again")
collatz(ask_for_number())
Now you can easily test the collatz() function independently from asking for a number from the user:
>>> collatz(45)
136
68
34
17
52
26
13
40
20
10
5
16
8
4
2
1

Is this what you're after?
def collatz(starting_value):
value = starting_value
while value != 1:
value = (3 * value + 1) if value % 2 else (value // 2)
yield value
if __name__ == '__main__':
start = int(input("Please enter starting value: "))
print(list(collatz(start)))
Example Run
Please enter starting value: 136
[68, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
How This Works
This code relies on the use of what are called generator functions - essentially, something that looks like a function but behaves like an iterator. collatz is the generator function and on each iteration it will produce the next term in the Collatz sequence.
When we execute the module containing this code directly, the Python interpreter will set its __name__ variable to '__main__', making the if statement at the bottom true.
Within that if block, we prompt the user for the value to start off the Collatz sequence. We assume they enter a valid number (anything else will cause an unhandled exception to be thrown).
The expression collatz(start) will produce a generator object that we can iterate over. We pass this object directly into list, which will keep asking the object to produce its next iteration over and over until it's exhausted. We really hope that Collatz' conjecture is true because otherwise this program might end up running forever!
Collatz' conjecture does seem to hold though, so eventually the while condition value != 1 becomes false, meaning that the generator object stops producing values. At that point, it will raise StopIteration to signal it has no more values, and list will return the complete list of Collatz terms that we then print.
The yield statement within collatz behaves similarly to return, except that the calling thread 'remembers' its position - when we ask for the next term in the sequence, it will carry on from that point, using the last stored values for the function's local variables (i.e. value).
Printing Terms Vertically
To print the terms vertically if you'd like, you can just iterate the generator within a for loop and print each term it yields on a new line:
if __name__ == '__main__':
start = int(input("Please enter starting value: "))
for term in collatz(start):
print(term)
Output
Please enter starting value: 136
68
34
17
52
26
13
40
20
10
5
16
8
4
2
1

if number%2 == 0:
print(number // 2)
else:
print(3 * number + 1)
You're not actually changing the value of number:
if number%2 == 0:
print(number // 2)
number = number // 2
else:
print(3 * number + 1)
number = 3 * number + 1

You forgot to update number
Try this :
def collatz():
try:
number = int(input("Please enter a number: "))
except ValueError:
collatz()
while number != 1:
if number%2 == 0:
number = number // 2
print(number)
else:
number = 3 * number + 1
print(number)
I hope it will help.

def collatz():
try:
number = int(input("Please enter a number: "))
except ValueError:
collatz()
while number != 1:
if number %2 ==0:
number = number // 2
else:
number = 3 * number + 1
print(number)
Printing doesn't set the actual value of number!

Several issues:
Main one: You never change the value of number.
Therefore your code should keep printing the same number over and over again.
Also you might want to check non-positive numbers.
But also when this is fixed, I suspect some unwanted behaviour when you run into the ValueError you catch.
You call the same function again. After completing this second run, the code will still try to run the next line and fails.
Example:
>>> collatz()
Please enter a number: "foo"
Please enter a number: 4
2
1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in collatz
UnboundLocalError: local variable 'number' referenced before assignment
My try to fix all of this:
def collatz():
number = 0
while number < 1:
try:
number = int(input("Please enter a number: "))
except ValueError, NameError:
pass
while number != 1:
if number%2 == 0:
number = number // 2
else:
number = 3 * number + 1
print(number)

Related

Automate The Boring Stuff - Collatz Sequence

I'm new to Python and I having issues with my Collatz Sequence project in the Automate the Boring Stuff book. When I run my code it "prints" 2 of each number. I can't figure out why it is duplicating each number. Anyone have any ideas?
Here are the directions to the short project:
Write a function named collatz() that has one parameter named number. If the number is even, then collatz() should print number // 2 and return this value. If the 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.
def collatz(number):
if number % 2 == 0:
print(number // 2)
return number // 2
elif number % 2 == 1:
print(3 * number + 1)
return 3 * number + 1
print('Enter number: ')
try:
x = int(input())
while x != 1:
collatz(x)
x = collatz(x)
except ValueError:
print('Please use whole numbers only')
When I enter the number 3 I get this:
Enter number:
3
10
10
5
5
16
16
8
8
4
4
2
2
1
1
Your issue is on the line:
while x != 1:
collatz(x)
x = collatz(x)
You are calling collatz twice, so it is printing each number twice.
Here is the debugged version:
def collatz(number):
if number % 2 == 0:
print(number // 2)
return number // 2
elif number % 2 == 1:
print(3 * number + 1)
return 3 * number + 1
print('Enter number: ')
try:
x = int(input())
while x != 1:
x = collatz(x)
except ValueError:
print('Please use whole numbers only')

using the calculation number for the next calculation

experts.
I'm trying to define a function (collatz) that:
Asks for a number. If it is even it prints number // 2, if it odd it prints 3 * number + 1. (OK)
The result, whatever it is, must enter a loop until the result is 1. (NOK)
So, i´m not figure out because the result is not used and is in an infinite loop. Any suggestion?
def collatz():
number = int(input('Enter the number: '))
x = number % 2
while number != 1:
if x == 0:
print(f'{number // 2}')
else:
print(f'{3 * number + 1}')
number = number
print(f'{collatz()}')
You need to actually assign the result back to number.
As well:
The divisibility check needs to be in the loop.
The outer print() is not needed.
The f-strings are redundant. print() converts its arguments to string automatically.
def collatz():
number = int(input('Enter the number: '))
while number != 1:
if number % 2 == 0:
number //= 2 # Short for "number = number // 2"
else:
number = 3*number + 1
print(number)
collatz()
Example run:
Enter the number: 3
10
5
16
8
4
2
1

hailstone program in python

i have to write a hailstone program in python
you pick a number, if it's even then half it, and if it's odd then multiply it by 3 and add 1 to it. it says to continue this pattern until the number becomes 1.
the program will need methods for the following:
accepting user input
when printing the sequence, the program should loop until the number 1.
print a count for the number of times the loop had to run to make the sequence.
here's a sample run:
prompt (input)
Enter a positive integer (1-1000). To quit, enter -1: 20
20 10 5 16 8 4 2 1
The loop executed 8 times.
Enter a positive integer (1-1000). To quit, enter -1: 30
30 15 46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1
The loop executed 19 times.
Enter a positive integer (1-1000). To quit, enter -1: -1
Thank you for playing Hailstone.
right now i have this:
count = 0
def hailstone(n):
if n > 0
print(n)
if n > 1:
if n % 2 == 0:
hailstone(n / 2)
else:
hailstone((n * 3) + 1)
count = count + 1
i don't know what to do after this
Try to think in a modular way, make two functions: check_number() and user_call(). Check_number will verify if the current number in the loop is odd or even and the user_call() just wraps it to count how many times the loop did iterate.
I found the exercise in a great book called Automate Boring Stuff with Python, you have to check it out, if you don't know it already.
Here's my code. Try to use what serves you the best.
from sys import exit
def check_number(number):
if number % 2 ==0:
print(number // 2)
return(number // 2)
else:
print(number*3+1)
return number*3+1
def user_call(number):
count = 0
while number != 1:
count += 1
number = check_number(number)
return count
if __name__ == "__main__":
try:
number = int(input('Give a number \n'))
count = user_call(number)
print('count ',count)
except Exception as e:
exit()
you can use global
visit https://www.programiz.com/python-programming/global-keyword to learn more
import sys
res = []
def hailstone(number):
global res
if number > 1:
if number % 2 == 0:
res.append( number // 2 )
hailstone(res[len(res)-1])
else:
res.append(number * 3 + 1)
hailstone(res[len(res)-1])
return res
number = int(input('Enter a positive integer. To quit, enter -1: '))
if number <= 0 or number == 0:
print('Thank you for playing Hailstone.')
sys.exit()
else:
answers = hailstone(number)
for answer in answers:
print(answer)
print('The loop executed {} times.'.format(len(answers) + 1))
I used recursion to solve the problem.
Heres my code:
Edit: All criteria met
count = 0
list_num = []
def input_check():
number = int(input("Enter a positive integer (1-1000). To quit, enter -1: "))
if number >= 1 and number <= 1000:
hailstone_game(number)
elif number == -1:
return
else:
print("Please type in a number between 1-1000")
input_check()
def hailstone_game(number):
global count
while number != 1:
count += 1
list_num.append(number)
if number % 2 == 0:
return hailstone_game(int(number/2))
else:
return hailstone_game(int(number*3+1))
list_num.append(1) # cheap uncreative way to add the one
print(*list_num, sep=" ")
print(f"The loop executed {count} times.")
return
input_check()
Additional stuff that could be done:
- Catching non-integer inputs using try / except
Keep in mind when programming it is a good habit to keep different functions of your code separate, by defining functions for each set of 'commands'. This leads to more readable and easier to maintain code. Of course in this situation it doesn't matter as the code is short.
Your recursive function is missing a base/terminating condition so it goes into an infinite loop.
resultArray = [] #list
def hailstone(n):
if n <= 0: # Base Condition
return
if n > 0:
resultArray.append(n)
if n > 1:
if n % 2 == 0:
hailstone(int(n/2))
else:
hailstone((n * 3) + 1)
# function call
hailstone(20)
print(len(resultArray), resultArray)
Output
8 [20, 10, 5, 16, 8, 4, 2, 1]
Here's a recursive approach for the problem.
count=0
def hailstone(n):
global count
count+=1
if n==1:
print(n)
else:
if n%2==0:
print(n)
hailstone(int(n/2))
else:
print(n)
hailstone(3*n+1)
hailstone(21)
print(f"Loop executed {count} times")

python for loop wont change value

So im new to python and this question should be fairly easy for anybody in here except me obvisouly haha so this is my code
for c in range(0,20):
print("number",c+1)
number = input ("Enter number:\n")
number = int(number)
if (number < 1 or number > 9):
print("try again by inputing a positive number < 10")
c -=1
so as you may think if the number someone inputs is bigger than 9 or smaller than 0 i just want my c to stay where it is so i get 20 positive numbers from 1-9 instead it doesnt do that and it keeps increasing even tho i have the c-=1 thingy down there
First, do not use range(0,20) but range(20) instead.
Second, range returns an iterator. This means, that when you do c-=1 you do not go back in the iterator, you decrease the number returned by the iterator. Meaning that if c=5 and the number you entered in input is 20, c will become 4, but when returning to the start of the loop, c be be 6.
You probably want something of this sort:
c = 0
while c < 20:
print("number",c+1)
number = input ("Enter number:\n")
number = int(number)
if (number < 1 or number > 9):
print("try again by inputing a positive number < 10")
continue
c += 1
an alternative and simple solution to this would be:
i=20
while(i!=0):
number = input("Enter number:\n")
number = int(number)
if (number <1 or number >9):
print("Invalid no try within 0-9 ")
else
print(number)
i-=1

Automate the boring tasks - exercise - collatz function

Beginner question here.
I have just attempted an exercise from Automate the boring stuff. I've completed the question in the format suggested by first defining a function as below:
"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."
and then using that same function, meeting those minimal constraints, to write a programme that meets the following requirements:
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.
I've managed to generate a sequence of numbers ending with one, following the above rules, but my program prints each number in the sequence three times. Is anyone able to explain why this might be?
Thanks so much for your help
def collatz(number):
if int(number) % 2 == 0:
print(int(number)//2)
return int(number)//2
else:
print(3 * int(number) + 1)
return 3 * int(number) + 1
collatz(5)
print('Enter a number')
entry = input()
while collatz(entry) != 1:
collatz(entry)
entry = collatz(entry)
Your loop should look like this:
entry = input()
while entry != 1:
entry = collatz(entry)
You are calling the function 3 times and you have a print call in the function.
Only call the function once and I would remove the print statements from the collatz method and just print in the calling loop, e.g.:
In []:
def collatz(number):
if number % 2 == 0:
return number//2
return 3*number + 1
entry = int(input("Enter a number: "))
print(entry)
while entry != 1:
entry = collatz(entry)
print(entry)
Out[]:
Enter a number: 10
10
5
16
8
4
2
1
You can try:
def collatz(number):
if number == 0:
return 'Try again with an integer other than 0'
elif number == 1:
return 1
elif number % 2 == 0:
n = number // 2
print(n)
elif number % 2 == 1:
n = 3 * number + 1
print(n)
while n != 1:
n = collatz(n)
return n
return n
The last statement return n in line 15 is optional.

Categories